Tue Jan 28 14:58:29 UTC 2025  I: starting to build errbot/unstable/i386 on jenkins on '2025-01-28 14:58'
Tue Jan 28 14:58:29 UTC 2025  I: The jenkins build log is/was available at https://jenkins.debian.net/userContent/reproducible/debian/build_service/i386_9/41771/console.log
Tue Jan 28 14:58:29 UTC 2025  I: Downloading source for unstable/errbot=6.2.0+ds-4
--2025-01-28 14:58:29--  http://deb.debian.org/debian/pool/main/e/errbot/errbot_6.2.0%2bds-4.dsc
Connecting to 46.16.76.132:3128... connected.
Proxy request sent, awaiting response... 200 OK
Length: 2233 (2.2K) [text/prs.lines.tag]
Saving to: ‘errbot_6.2.0+ds-4.dsc’

     0K ..                                                    100%  342M=0s

2025-01-28 14:58:29 (342 MB/s) - ‘errbot_6.2.0+ds-4.dsc’ saved [2233/2233]

Tue Jan 28 14:58:29 UTC 2025  I: errbot_6.2.0+ds-4.dsc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 3.0 (quilt)
Source: errbot
Binary: errbot
Architecture: all
Version: 6.2.0+ds-4
Maintainer: Debian Python Team <team+python@tracker.debian.org>
Uploaders: Birger Schacht <birger@debian.org>
Homepage: http://errbot.io
Standards-Version: 4.5.1
Vcs-Browser: https://salsa.debian.org/python-team/packages/errbot
Vcs-Git: https://salsa.debian.org/python-team/packages/errbot.git
Build-Depends: debhelper-compat (= 13), dh-sequence-python3, git-core, localehelper, python3-all, python3-ansi, python3-bottle, python3-colorlog, python3-daemonize, python3-flask, python3-jinja2, python3-markdown, python3-openssl, python3-pygments, python3-pytest, python3-requests, python3-setuptools, python3-webtest, python3-yapsy, python3-dulwich
Package-List:
 errbot deb net optional arch=all
Checksums-Sha1:
 b23eaa6a5b0e436861b433da2aededefa754985c 1341096 errbot_6.2.0+ds.orig.tar.xz
 671fe4358d85bd1bdd6472259fb36f410f654fb5 7412 errbot_6.2.0+ds-4.debian.tar.xz
Checksums-Sha256:
 5a9bd3ce367906518960493f56e2c547047435c02581d4e3cef5c5f6255cb18a 1341096 errbot_6.2.0+ds.orig.tar.xz
 be45ae630c90777d33da6b3d986488f103e11add0edd99f6ff4247e10cfd3074 7412 errbot_6.2.0+ds-4.debian.tar.xz
Files:
 8c91bbd9f785227ef8a1747e464fa86e 1341096 errbot_6.2.0+ds.orig.tar.xz
 7b3d51bb8099646560ee85ef0264b860 7412 errbot_6.2.0+ds-4.debian.tar.xz

-----BEGIN PGP SIGNATURE-----

iQJFBAEBCgAvFiEEj23hBDd/OxHnQXSHMfMURUShdBoFAmeYDGgRHHRjaGV0QGRl
Ymlhbi5vcmcACgkQMfMURUShdBpl1RAAkimq/urVrSs0L6HP0k8D6sULn9gL8zIb
q+b47y2bDTUoa4Lgomfc9LR3WrQFhUz083W0eE6S+1/qCz7pePHCLN8qk6iiZwrb
J/l0PTPsaVCKq1Rsq/S/ObQzc4QfBu+UgErVjQHpp5FrTEucDHYfTaWEvKbYHly9
TshAlKcLLPY9SZ86BU05emnKHK4vzSxD70Ehxi/BrE6joSh2WU+hm1OGPy738y9p
PdEEyYjfN3dyMGtarqStVX3P81t/QRmKYW9fY1rTvg6eaSoIgPVKKrOw2NhGZ/z8
OOkuEWus2S6AVemBY1wZOZjJNlEJaXQFBnS+MIUaLbRww976IGU9Qh+OtpHoOxdW
j5gO0hLO3iNWiD4kE9k8enSPKQpQ4D2cgvQAqP56AGVb6+ZyG/60gxKP4TCClgFQ
ykylgEuKRqe1lXTaenvw5ht/j/z/4O4AbtCY8KfSESTfcfK4hY6q9ZgbIJaB34GO
aQdyLqBT1wa1hmX43TXAgS/vRgY2ZIahAb7/8u2Cn32ZKlQDvD5qiaKGchay6iFu
yK1gHTCHVrTc9NmP2i9h4gOf0SViD7IgdCe/o4AI+JgaPiUdMwddCwqB11/FFUm9
mmCAWIxlbo8dVjst+aEr0yukzVsIfZef4txZ6h5g8CS+NSef2F8yUDSkYZc5aFoM
uIlsRpfFl0o=
=e8nH
-----END PGP SIGNATURE-----
Tue Jan 28 14:58:29 UTC 2025  I: Checking whether the package is not for us
Tue Jan 28 14:58:29 UTC 2025  I: Starting 1st build on remote node ionos2-i386.debian.net.
Tue Jan 28 14:58:29 UTC 2025  I: Preparing to do remote build '1' on ionos2-i386.debian.net.
Tue Jan 28 15:00:29 UTC 2025  I: Deleting $TMPDIR on ionos2-i386.debian.net.
I: pbuilder: network access will be disabled during build
I: Current time: Tue Jan 28 02:58:31 -12 2025
I: pbuilder-time-stamp: 1738076311
I: Building the build Environment
I: extracting base tarball [/var/cache/pbuilder/unstable-reproducible-base.tgz]
I: copying local configuration
W: --override-config is not set; not updating apt.conf Read the manpage for details.
I: mounting /proc filesystem
I: mounting /sys filesystem
I: creating /{dev,run}/shm
I: mounting /dev/pts filesystem
I: redirecting /dev/ptmx to /dev/pts/ptmx
I: policy-rc.d already exists
I: using eatmydata during job
I: Copying source file
I: copying [errbot_6.2.0+ds-4.dsc]
I: copying [./errbot_6.2.0+ds.orig.tar.xz]
I: copying [./errbot_6.2.0+ds-4.debian.tar.xz]
I: Extracting source
dpkg-source: warning: cannot verify inline signature for ./errbot_6.2.0+ds-4.dsc: unsupported subcommand
dpkg-source: info: extracting errbot in errbot-6.2.0+ds
dpkg-source: info: unpacking errbot_6.2.0+ds.orig.tar.xz
dpkg-source: info: unpacking errbot_6.2.0+ds-4.debian.tar.xz
dpkg-source: info: using patch list from debian/patches/series
dpkg-source: info: applying 0002-Remove-pygments-markdown-lexer-dependency.patch
dpkg-source: info: applying SyntaxWarning.patch
I: Not using root during the build.
I: Installing the build-deps
I: user script /srv/workspace/pbuilder/56873/tmp/hooks/D02_print_environment starting
I: set
  BUILDDIR='/build/reproducible-path'
  BUILDUSERGECOS='first user,first room,first work-phone,first home-phone,first other'
  BUILDUSERNAME='pbuilder1'
  BUILD_ARCH='i386'
  DEBIAN_FRONTEND='noninteractive'
  DEB_BUILD_OPTIONS='buildinfo=+all reproducible=+all parallel=11 '
  DISTRIBUTION='unstable'
  HOME='/root'
  HOST_ARCH='i386'
  IFS=' 	
  '
  INVOCATION_ID='c541cd49783d4fc98556ef6f489b0cad'
  LANG='C'
  LANGUAGE='en_US:en'
  LC_ALL='C'
  LD_LIBRARY_PATH='/usr/lib/libeatmydata'
  LD_PRELOAD='libeatmydata.so'
  MAIL='/var/mail/root'
  OPTIND='1'
  PATH='/usr/sbin:/usr/bin:/sbin:/bin:/usr/games'
  PBCURRENTCOMMANDLINEOPERATION='build'
  PBUILDER_OPERATION='build'
  PBUILDER_PKGDATADIR='/usr/share/pbuilder'
  PBUILDER_PKGLIBDIR='/usr/lib/pbuilder'
  PBUILDER_SYSCONFDIR='/etc'
  PPID='56873'
  PS1='# '
  PS2='> '
  PS4='+ '
  PWD='/'
  SHELL='/bin/bash'
  SHLVL='2'
  SUDO_COMMAND='/usr/bin/timeout -k 18.1h 18h /usr/bin/ionice -c 3 /usr/bin/nice /usr/sbin/pbuilder --build --configfile /srv/reproducible-results/rbuild-debian/r-b-build.liI1fjO0/pbuilderrc_XyoZ --distribution unstable --hookdir /etc/pbuilder/first-build-hooks --debbuildopts -b --basetgz /var/cache/pbuilder/unstable-reproducible-base.tgz --buildresult /srv/reproducible-results/rbuild-debian/r-b-build.liI1fjO0/b1 --logfile b1/build.log errbot_6.2.0+ds-4.dsc'
  SUDO_GID='112'
  SUDO_UID='107'
  SUDO_USER='jenkins'
  TERM='unknown'
  TZ='/usr/share/zoneinfo/Etc/GMT+12'
  USER='root'
  _='/usr/bin/systemd-run'
  http_proxy='http://46.16.76.132:3128'
I: uname -a
  Linux ionos2-i386 6.1.0-30-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.124-1 (2025-01-12) x86_64 GNU/Linux
I: ls -l /bin
  lrwxrwxrwx 1 root root 7 Nov 22 14:40 /bin -> usr/bin
I: user script /srv/workspace/pbuilder/56873/tmp/hooks/D02_print_environment finished
 -> Attempting to satisfy build-dependencies
 -> Creating pbuilder-satisfydepends-dummy package
Package: pbuilder-satisfydepends-dummy
Version: 0.invalid.0
Architecture: i386
Maintainer: Debian Pbuilder Team <pbuilder-maint@lists.alioth.debian.org>
Description: Dummy package to satisfy dependencies with aptitude - created by pbuilder
 This package was created automatically by pbuilder to satisfy the
 build-dependencies of the package being currently built.
Depends: debhelper-compat (= 13), dh-sequence-python3, git-core, localehelper, python3-all, python3-ansi, python3-bottle, python3-colorlog, python3-daemonize, python3-flask, python3-jinja2, python3-markdown, python3-openssl, python3-pygments, python3-pytest, python3-requests, python3-setuptools, python3-webtest, python3-yapsy, python3-dulwich
dpkg-deb: building package 'pbuilder-satisfydepends-dummy' in '/tmp/satisfydepends-aptitude/pbuilder-satisfydepends-dummy.deb'.
Selecting previously unselected package pbuilder-satisfydepends-dummy.
(Reading database ... 19829 files and directories currently installed.)
Preparing to unpack .../pbuilder-satisfydepends-dummy.deb ...
Unpacking pbuilder-satisfydepends-dummy (0.invalid.0) ...
dpkg: pbuilder-satisfydepends-dummy: dependency problems, but configuring anyway as you requested:
 pbuilder-satisfydepends-dummy depends on debhelper-compat (= 13); however:
  Package debhelper-compat is not installed.
 pbuilder-satisfydepends-dummy depends on dh-sequence-python3; however:
  Package dh-sequence-python3 is not installed.
 pbuilder-satisfydepends-dummy depends on git-core; however:
  Package git-core is not installed.
 pbuilder-satisfydepends-dummy depends on localehelper; however:
  Package localehelper is not installed.
 pbuilder-satisfydepends-dummy depends on python3-all; however:
  Package python3-all is not installed.
 pbuilder-satisfydepends-dummy depends on python3-ansi; however:
  Package python3-ansi is not installed.
 pbuilder-satisfydepends-dummy depends on python3-bottle; however:
  Package python3-bottle is not installed.
 pbuilder-satisfydepends-dummy depends on python3-colorlog; however:
  Package python3-colorlog is not installed.
 pbuilder-satisfydepends-dummy depends on python3-daemonize; however:
  Package python3-daemonize is not installed.
 pbuilder-satisfydepends-dummy depends on python3-flask; however:
  Package python3-flask is not installed.
 pbuilder-satisfydepends-dummy depends on python3-jinja2; however:
  Package python3-jinja2 is not installed.
 pbuilder-satisfydepends-dummy depends on python3-markdown; however:
  Package python3-markdown is not installed.
 pbuilder-satisfydepends-dummy depends on python3-openssl; however:
  Package python3-openssl is not installed.
 pbuilder-satisfydepends-dummy depends on python3-pygments; however:
  Package python3-pygments is not installed.
 pbuilder-satisfydepends-dummy depends on python3-pytest; however:
  Package python3-pytest is not installed.
 pbuilder-satisfydepends-dummy depends on python3-requests; however:
  Package python3-requests is not installed.
 pbuilder-satisfydepends-dummy depends on python3-setuptools; however:
  Package python3-setuptools is not installed.
 pbuilder-satisfydepends-dummy depends on python3-webtest; however:
  Package python3-webtest is not installed.
 pbuilder-satisfydepends-dummy depends on python3-yapsy; however:
  Package python3-yapsy is not installed.
 pbuilder-satisfydepends-dummy depends on python3-dulwich; however:
  Package python3-dulwich is not installed.

Setting up pbuilder-satisfydepends-dummy (0.invalid.0) ...
Reading package lists...
Building dependency tree...
Reading state information...
Initializing package states...
Writing extended state information...
Building tag database...
pbuilder-satisfydepends-dummy is already installed at the requested version (0.invalid.0)
pbuilder-satisfydepends-dummy is already installed at the requested version (0.invalid.0)
The following NEW packages will be installed:
  autoconf{a} automake{a} autopoint{a} autotools-dev{a} bsdextrautils{a} ca-certificates{a} debhelper{a} dh-autoreconf{a} dh-python{a} dh-strip-nondeterminism{a} dwz{a} file{a} gettext{a} gettext-base{a} git{a} git-man{a} groff-base{a} intltool-debian{a} libarchive-zip-perl{a} libbrotli1{a} libcom-err2{a} libcurl3t64-gnutls{a} libdebhelper-perl{a} libelf1t64{a} liberror-perl{a} libexpat1{a} libffi8{a} libfile-stripnondeterminism-perl{a} libgnutls30t64{a} libgssapi-krb5-2{a} libicu72{a} libidn2-0{a} libk5crypto3{a} libkeyutils1{a} libkrb5-3{a} libkrb5support0{a} libldap2{a} libmagic-mgc{a} libmagic1t64{a} libnghttp2-14{a} libnghttp3-9{a} libngtcp2-16{a} libngtcp2-crypto-gnutls8{a} libnsl2{a} libp11-kit0{a} libpipeline1{a} libpsl5t64{a} libpython3-stdlib{a} libpython3.12-minimal{a} libpython3.12-stdlib{a} libpython3.13-minimal{a} libpython3.13-stdlib{a} libreadline8t64{a} librtmp1{a} libsasl2-2{a} libsasl2-modules-db{a} libssh2-1t64{a} libtasn1-6{a} libtirpc-common{a} libtirpc3t64{a} libtool{a} libuchardet0{a} libunistring5{a} libxml2{a} localehelper{a} locales{a} m4{a} man-db{a} media-types{a} netbase{a} openssl{a} po-debconf{a} python3{a} python3-all{a} python3-ansi{a} python3-autocommand{a} python3-bcrypt{a} python3-blinker{a} python3-bottle{a} python3-bs4{a} python3-certifi{a} python3-cffi-backend{a} python3-chardet{a} python3-charset-normalizer{a} python3-click{a} python3-colorlog{a} python3-cryptography{a} python3-daemonize{a} python3-dulwich{a} python3-flask{a} python3-idna{a} python3-inflect{a} python3-iniconfig{a} python3-itsdangerous{a} python3-jaraco.context{a} python3-jaraco.functools{a} python3-jaraco.text{a} python3-jinja2{a} python3-legacy-cgi{a} python3-markdown{a} python3-markupsafe{a} python3-minimal{a} python3-more-itertools{a} python3-openssl{a} python3-packaging{a} python3-paste{a} python3-pastedeploy{a} python3-pastedeploy-tpl{a} python3-pkg-resources{a} python3-pluggy{a} python3-pygments{a} python3-pytest{a} python3-requests{a} python3-setuptools{a} python3-soupsieve{a} python3-tempita{a} python3-typeguard{a} python3-typing-extensions{a} python3-urllib3{a} python3-waitress{a} python3-webob{a} python3-webtest{a} python3-werkzeug{a} python3-yapsy{a} python3-zipp{a} python3.12{a} python3.12-minimal{a} python3.13{a} python3.13-minimal{a} readline-common{a} sensible-utils{a} tzdata{a} 
The following packages are RECOMMENDED but will NOT be installed:
  curl krb5-locales less libarchive-cpio-perl libldap-common libltdl-dev libmail-sendmail-perl libsasl2-modules lynx openssh-client publicsuffix python3-asgiref python3-babel python3-dotenv python3-fastimport python3-lxml python3-pastescript python3-pyinotify python3-yaml wget 
0 packages upgraded, 132 newly installed, 0 to remove and 0 not upgraded.
Need to get 60.7 MB of archives. After unpacking 246 MB will be used.
Writing extended state information...
Get: 1 http://deb.debian.org/debian unstable/main i386 libpython3.13-minimal i386 3.13.1-3 [858 kB]
Get: 2 http://deb.debian.org/debian unstable/main i386 libexpat1 i386 2.6.4-1 [107 kB]
Get: 3 http://deb.debian.org/debian unstable/main i386 python3.13-minimal i386 3.13.1-3 [2264 kB]
Get: 4 http://deb.debian.org/debian unstable/main i386 python3-minimal i386 3.13.1-2 [27.0 kB]
Get: 5 http://deb.debian.org/debian unstable/main i386 media-types all 10.1.0 [26.9 kB]
Get: 6 http://deb.debian.org/debian unstable/main i386 netbase all 6.4 [12.8 kB]
Get: 7 http://deb.debian.org/debian unstable/main i386 tzdata all 2025a-1 [259 kB]
Get: 8 http://deb.debian.org/debian unstable/main i386 libffi8 i386 3.4.6-1 [21.2 kB]
Get: 9 http://deb.debian.org/debian unstable/main i386 readline-common all 8.2-6 [69.4 kB]
Get: 10 http://deb.debian.org/debian unstable/main i386 libreadline8t64 i386 8.2-6 [173 kB]
Get: 11 http://deb.debian.org/debian unstable/main i386 libpython3.13-stdlib i386 3.13.1-3 [1980 kB]
Get: 12 http://deb.debian.org/debian unstable/main i386 python3.13 i386 3.13.1-3 [740 kB]
Get: 13 http://deb.debian.org/debian unstable/main i386 libpython3-stdlib i386 3.13.1-2 [9952 B]
Get: 14 http://deb.debian.org/debian unstable/main i386 python3 i386 3.13.1-2 [28.0 kB]
Get: 15 http://deb.debian.org/debian unstable/main i386 libpython3.12-minimal i386 3.12.8-5 [816 kB]
Get: 16 http://deb.debian.org/debian unstable/main i386 python3.12-minimal i386 3.12.8-5 [2241 kB]
Get: 17 http://deb.debian.org/debian unstable/main i386 sensible-utils all 0.0.24 [24.8 kB]
Get: 18 http://deb.debian.org/debian unstable/main i386 openssl i386 3.4.0-2 [1427 kB]
Get: 19 http://deb.debian.org/debian unstable/main i386 ca-certificates all 20241223 [164 kB]
Get: 20 http://deb.debian.org/debian unstable/main i386 libmagic-mgc i386 1:5.45-3+b1 [314 kB]
Get: 21 http://deb.debian.org/debian unstable/main i386 libmagic1t64 i386 1:5.45-3+b1 [115 kB]
Get: 22 http://deb.debian.org/debian unstable/main i386 file i386 1:5.45-3+b1 [43.2 kB]
Get: 23 http://deb.debian.org/debian unstable/main i386 gettext-base i386 0.23.1-1 [245 kB]
Get: 24 http://deb.debian.org/debian unstable/main i386 libuchardet0 i386 0.0.8-1+b2 [69.2 kB]
Get: 25 http://deb.debian.org/debian unstable/main i386 groff-base i386 1.23.0-7 [1199 kB]
Get: 26 http://deb.debian.org/debian unstable/main i386 locales all 2.40-6 [3901 kB]
Get: 27 http://deb.debian.org/debian unstable/main i386 bsdextrautils i386 2.40.4-2 [96.1 kB]
Get: 28 http://deb.debian.org/debian unstable/main i386 libpipeline1 i386 1.5.8-1 [41.2 kB]
Get: 29 http://deb.debian.org/debian unstable/main i386 man-db i386 2.13.0-1 [1428 kB]
Get: 30 http://deb.debian.org/debian unstable/main i386 m4 i386 1.4.19-5 [301 kB]
Get: 31 http://deb.debian.org/debian unstable/main i386 autoconf all 2.72-3 [493 kB]
Get: 32 http://deb.debian.org/debian unstable/main i386 autotools-dev all 20220109.1 [51.6 kB]
Get: 33 http://deb.debian.org/debian unstable/main i386 automake all 1:1.17-2 [861 kB]
Get: 34 http://deb.debian.org/debian unstable/main i386 autopoint all 0.23.1-1 [770 kB]
Get: 35 http://deb.debian.org/debian unstable/main i386 libdebhelper-perl all 13.24.1 [90.9 kB]
Get: 36 http://deb.debian.org/debian unstable/main i386 libtool all 2.5.4-2 [539 kB]
Get: 37 http://deb.debian.org/debian unstable/main i386 dh-autoreconf all 20 [17.1 kB]
Get: 38 http://deb.debian.org/debian unstable/main i386 libarchive-zip-perl all 1.68-1 [104 kB]
Get: 39 http://deb.debian.org/debian unstable/main i386 libfile-stripnondeterminism-perl all 1.14.1-1 [19.6 kB]
Get: 40 http://deb.debian.org/debian unstable/main i386 dh-strip-nondeterminism all 1.14.1-1 [8584 B]
Get: 41 http://deb.debian.org/debian unstable/main i386 libelf1t64 i386 0.192-4 [195 kB]
Get: 42 http://deb.debian.org/debian unstable/main i386 dwz i386 0.15-1+b1 [116 kB]
Get: 43 http://deb.debian.org/debian unstable/main i386 libunistring5 i386 1.3-1 [458 kB]
Get: 44 http://deb.debian.org/debian unstable/main i386 libicu72 i386 72.1-6 [9582 kB]
Get: 45 http://deb.debian.org/debian unstable/main i386 libxml2 i386 2.12.7+dfsg+really2.9.14-0.2+b1 [734 kB]
Get: 46 http://deb.debian.org/debian unstable/main i386 gettext i386 0.23.1-1 [1714 kB]
Get: 47 http://deb.debian.org/debian unstable/main i386 intltool-debian all 0.35.0+20060710.6 [22.9 kB]
Get: 48 http://deb.debian.org/debian unstable/main i386 po-debconf all 1.0.21+nmu1 [248 kB]
Get: 49 http://deb.debian.org/debian unstable/main i386 debhelper all 13.24.1 [920 kB]
Get: 50 http://deb.debian.org/debian unstable/main i386 python3-autocommand all 2.2.2-3 [13.6 kB]
Get: 51 http://deb.debian.org/debian unstable/main i386 python3-more-itertools all 10.6.0-1 [65.3 kB]
Get: 52 http://deb.debian.org/debian unstable/main i386 python3-typing-extensions all 4.12.2-2 [73.0 kB]
Get: 53 http://deb.debian.org/debian unstable/main i386 python3-typeguard all 4.4.1-1 [37.0 kB]
Get: 54 http://deb.debian.org/debian unstable/main i386 python3-inflect all 7.3.1-2 [32.4 kB]
Get: 55 http://deb.debian.org/debian unstable/main i386 python3-jaraco.context all 6.0.0-1 [7984 B]
Get: 56 http://deb.debian.org/debian unstable/main i386 python3-jaraco.functools all 4.1.0-1 [12.0 kB]
Get: 57 http://deb.debian.org/debian unstable/main i386 python3-pkg-resources all 75.6.0-1 [222 kB]
Get: 58 http://deb.debian.org/debian unstable/main i386 python3-jaraco.text all 4.0.0-1 [11.4 kB]
Get: 59 http://deb.debian.org/debian unstable/main i386 python3-zipp all 3.21.0-1 [10.6 kB]
Get: 60 http://deb.debian.org/debian unstable/main i386 python3-setuptools all 75.6.0-1 [720 kB]
Get: 61 http://deb.debian.org/debian unstable/main i386 dh-python all 6.20250108 [113 kB]
Get: 62 http://deb.debian.org/debian unstable/main i386 libbrotli1 i386 1.1.0-2+b6 [308 kB]
Get: 63 http://deb.debian.org/debian unstable/main i386 libidn2-0 i386 2.3.7-2+b1 [130 kB]
Get: 64 http://deb.debian.org/debian unstable/main i386 libp11-kit0 i386 0.25.5-3 [423 kB]
Get: 65 http://deb.debian.org/debian unstable/main i386 libtasn1-6 i386 4.19.0-3+b3 [51.1 kB]
Get: 66 http://deb.debian.org/debian unstable/main i386 libgnutls30t64 i386 3.8.8-2 [1451 kB]
Get: 67 http://deb.debian.org/debian unstable/main i386 libkrb5support0 i386 1.21.3-4 [35.0 kB]
Get: 68 http://deb.debian.org/debian unstable/main i386 libcom-err2 i386 1.47.2-1 [24.3 kB]
Get: 69 http://deb.debian.org/debian unstable/main i386 libk5crypto3 i386 1.21.3-4 [83.7 kB]
Get: 70 http://deb.debian.org/debian unstable/main i386 libkeyutils1 i386 1.6.3-4 [9600 B]
Get: 71 http://deb.debian.org/debian unstable/main i386 libkrb5-3 i386 1.21.3-4 [354 kB]
Get: 72 http://deb.debian.org/debian unstable/main i386 libgssapi-krb5-2 i386 1.21.3-4 [149 kB]
Get: 73 http://deb.debian.org/debian unstable/main i386 libsasl2-modules-db i386 2.1.28+dfsg1-8+b1 [20.9 kB]
Get: 74 http://deb.debian.org/debian unstable/main i386 libsasl2-2 i386 2.1.28+dfsg1-8+b1 [61.3 kB]
Get: 75 http://deb.debian.org/debian unstable/main i386 libldap2 i386 2.6.9+dfsg-1 [205 kB]
Get: 76 http://deb.debian.org/debian unstable/main i386 libnghttp2-14 i386 1.64.0-1 [82.4 kB]
Get: 77 http://deb.debian.org/debian unstable/main i386 libnghttp3-9 i386 1.6.0-2 [75.9 kB]
Get: 78 http://deb.debian.org/debian unstable/main i386 libngtcp2-16 i386 1.9.1-1 [151 kB]
Get: 79 http://deb.debian.org/debian unstable/main i386 libngtcp2-crypto-gnutls8 i386 1.9.1-1 [19.1 kB]
Get: 80 http://deb.debian.org/debian unstable/main i386 libpsl5t64 i386 0.21.2-1.1+b1 [57.7 kB]
Get: 81 http://deb.debian.org/debian unstable/main i386 librtmp1 i386 2.4+20151223.gitfa8646d.1-2+b5 [62.4 kB]
Get: 82 http://deb.debian.org/debian unstable/main i386 libssh2-1t64 i386 1.11.1-1 [256 kB]
Get: 83 http://deb.debian.org/debian unstable/main i386 libcurl3t64-gnutls i386 8.11.1-1+b1 [404 kB]
Get: 84 http://deb.debian.org/debian unstable/main i386 liberror-perl all 0.17029-2 [29.0 kB]
Get: 85 http://deb.debian.org/debian unstable/main i386 git-man all 1:2.47.2-0.1 [2205 kB]
Get: 86 http://deb.debian.org/debian unstable/main i386 git i386 1:2.47.2-0.1 [9337 kB]
Get: 87 http://deb.debian.org/debian unstable/main i386 libtirpc-common all 1.3.4+ds-1.3 [10.9 kB]
Get: 88 http://deb.debian.org/debian unstable/main i386 libtirpc3t64 i386 1.3.4+ds-1.3+b1 [90.5 kB]
Get: 89 http://deb.debian.org/debian unstable/main i386 libnsl2 i386 1.3.0-3+b3 [42.7 kB]
Get: 90 http://deb.debian.org/debian unstable/main i386 libpython3.12-stdlib i386 3.12.8-5 [1969 kB]
Get: 91 http://deb.debian.org/debian unstable/main i386 localehelper all 0.1.4-3.1 [7928 B]
Get: 92 http://deb.debian.org/debian unstable/main i386 python3.12 i386 3.12.8-5 [677 kB]
Get: 93 http://deb.debian.org/debian unstable/main i386 python3-all i386 3.13.1-2 [1052 B]
Get: 94 http://deb.debian.org/debian unstable/main i386 python3-ansi all 0.1.5-2 [6232 B]
Get: 95 http://deb.debian.org/debian unstable/main i386 python3-bcrypt i386 4.2.0-2.1 [248 kB]
Get: 96 http://deb.debian.org/debian unstable/main i386 python3-blinker all 1.9.0-1 [12.6 kB]
Get: 97 http://deb.debian.org/debian unstable/main i386 python3-bottle all 0.13.2-1.1 [54.3 kB]
Get: 98 http://deb.debian.org/debian unstable/main i386 python3-soupsieve all 2.6-1 [38.3 kB]
Get: 99 http://deb.debian.org/debian unstable/main i386 python3-bs4 all 4.12.3-3 [133 kB]
Get: 100 http://deb.debian.org/debian unstable/main i386 python3-certifi all 2024.12.14+ds-1 [9624 B]
Get: 101 http://deb.debian.org/debian unstable/main i386 python3-cffi-backend i386 1.17.1-2+b1 [95.5 kB]
Get: 102 http://deb.debian.org/debian unstable/main i386 python3-chardet all 5.2.0+dfsg-2 [108 kB]
Get: 103 http://deb.debian.org/debian unstable/main i386 python3-charset-normalizer i386 3.4.0-1+b1 [139 kB]
Get: 104 http://deb.debian.org/debian unstable/main i386 python3-click all 8.1.8-1 [95.2 kB]
Get: 105 http://deb.debian.org/debian unstable/main i386 python3-colorlog all 6.9.0-1 [27.5 kB]
Get: 106 http://deb.debian.org/debian unstable/main i386 python3-cryptography i386 43.0.0-1 [975 kB]
Get: 107 http://deb.debian.org/debian unstable/main i386 python3-daemonize all 2.5.0-3 [6324 B]
Get: 108 http://deb.debian.org/debian unstable/main i386 python3-urllib3 all 2.3.0-1 [114 kB]
Get: 109 http://deb.debian.org/debian unstable/main i386 python3-dulwich i386 0.22.7-1 [205 kB]
Get: 110 http://deb.debian.org/debian unstable/main i386 python3-itsdangerous all 2.2.0-2 [18.1 kB]
Get: 111 http://deb.debian.org/debian unstable/main i386 python3-markupsafe i386 2.1.5-1+b2 [13.9 kB]
Get: 112 http://deb.debian.org/debian unstable/main i386 python3-jinja2 all 3.1.5-1 [107 kB]
Get: 113 http://deb.debian.org/debian unstable/main i386 python3-werkzeug all 3.1.3-2 [207 kB]
Get: 114 http://deb.debian.org/debian unstable/main i386 python3-flask all 3.1.0-2 [106 kB]
Get: 115 http://deb.debian.org/debian unstable/main i386 python3-idna all 3.8-2 [41.6 kB]
Get: 116 http://deb.debian.org/debian unstable/main i386 python3-iniconfig all 1.1.1-2 [6396 B]
Get: 117 http://deb.debian.org/debian unstable/main i386 python3-legacy-cgi all 2.6.1-2 [16.1 kB]
Get: 118 http://deb.debian.org/debian unstable/main i386 python3-markdown all 3.7-2 [85.2 kB]
Get: 119 http://deb.debian.org/debian unstable/main i386 python3-openssl all 25.0.0-1 [52.1 kB]
Get: 120 http://deb.debian.org/debian unstable/main i386 python3-packaging all 24.2-1 [55.3 kB]
Get: 121 http://deb.debian.org/debian unstable/main i386 python3-tempita all 0.6.0-1 [14.6 kB]
Get: 122 http://deb.debian.org/debian unstable/main i386 python3-paste all 3.10.1-1 [222 kB]
Get: 123 http://deb.debian.org/debian unstable/main i386 python3-pastedeploy-tpl all 3.1-1 [8268 B]
Get: 124 http://deb.debian.org/debian unstable/main i386 python3-pastedeploy all 3.1-1 [18.3 kB]
Get: 125 http://deb.debian.org/debian unstable/main i386 python3-pluggy all 1.5.0-1 [26.9 kB]
Get: 126 http://deb.debian.org/debian unstable/main i386 python3-pygments all 2.18.0+dfsg-2 [836 kB]
Get: 127 http://deb.debian.org/debian unstable/main i386 python3-pytest all 8.3.4-1 [250 kB]
Get: 128 http://deb.debian.org/debian unstable/main i386 python3-requests all 2.32.3+dfsg-1 [71.9 kB]
Get: 129 http://deb.debian.org/debian unstable/main i386 python3-waitress all 3.0.2-1 [46.5 kB]
Get: 130 http://deb.debian.org/debian unstable/main i386 python3-webob all 1:1.8.9-1 [89.1 kB]
Get: 131 http://deb.debian.org/debian unstable/main i386 python3-webtest all 3.0.2-1 [35.2 kB]
Get: 132 http://deb.debian.org/debian unstable/main i386 python3-yapsy all 1.12.2-3 [30.4 kB]
Fetched 60.7 MB in 1s (68.0 MB/s)
Preconfiguring packages ...
Selecting previously unselected package libpython3.13-minimal:i386.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 19829 files and directories currently installed.)
Preparing to unpack .../libpython3.13-minimal_3.13.1-3_i386.deb ...
Unpacking libpython3.13-minimal:i386 (3.13.1-3) ...
Selecting previously unselected package libexpat1:i386.
Preparing to unpack .../libexpat1_2.6.4-1_i386.deb ...
Unpacking libexpat1:i386 (2.6.4-1) ...
Selecting previously unselected package python3.13-minimal.
Preparing to unpack .../python3.13-minimal_3.13.1-3_i386.deb ...
Unpacking python3.13-minimal (3.13.1-3) ...
Setting up libpython3.13-minimal:i386 (3.13.1-3) ...
Setting up libexpat1:i386 (2.6.4-1) ...
Setting up python3.13-minimal (3.13.1-3) ...
Selecting previously unselected package python3-minimal.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 20163 files and directories currently installed.)
Preparing to unpack .../0-python3-minimal_3.13.1-2_i386.deb ...
Unpacking python3-minimal (3.13.1-2) ...
Selecting previously unselected package media-types.
Preparing to unpack .../1-media-types_10.1.0_all.deb ...
Unpacking media-types (10.1.0) ...
Selecting previously unselected package netbase.
Preparing to unpack .../2-netbase_6.4_all.deb ...
Unpacking netbase (6.4) ...
Selecting previously unselected package tzdata.
Preparing to unpack .../3-tzdata_2025a-1_all.deb ...
Unpacking tzdata (2025a-1) ...
Selecting previously unselected package libffi8:i386.
Preparing to unpack .../4-libffi8_3.4.6-1_i386.deb ...
Unpacking libffi8:i386 (3.4.6-1) ...
Selecting previously unselected package readline-common.
Preparing to unpack .../5-readline-common_8.2-6_all.deb ...
Unpacking readline-common (8.2-6) ...
Selecting previously unselected package libreadline8t64:i386.
Preparing to unpack .../6-libreadline8t64_8.2-6_i386.deb ...
Adding 'diversion of /lib/i386-linux-gnu/libhistory.so.8 to /lib/i386-linux-gnu/libhistory.so.8.usr-is-merged by libreadline8t64'
Adding 'diversion of /lib/i386-linux-gnu/libhistory.so.8.2 to /lib/i386-linux-gnu/libhistory.so.8.2.usr-is-merged by libreadline8t64'
Adding 'diversion of /lib/i386-linux-gnu/libreadline.so.8 to /lib/i386-linux-gnu/libreadline.so.8.usr-is-merged by libreadline8t64'
Adding 'diversion of /lib/i386-linux-gnu/libreadline.so.8.2 to /lib/i386-linux-gnu/libreadline.so.8.2.usr-is-merged by libreadline8t64'
Unpacking libreadline8t64:i386 (8.2-6) ...
Selecting previously unselected package libpython3.13-stdlib:i386.
Preparing to unpack .../7-libpython3.13-stdlib_3.13.1-3_i386.deb ...
Unpacking libpython3.13-stdlib:i386 (3.13.1-3) ...
Selecting previously unselected package python3.13.
Preparing to unpack .../8-python3.13_3.13.1-3_i386.deb ...
Unpacking python3.13 (3.13.1-3) ...
Selecting previously unselected package libpython3-stdlib:i386.
Preparing to unpack .../9-libpython3-stdlib_3.13.1-2_i386.deb ...
Unpacking libpython3-stdlib:i386 (3.13.1-2) ...
Setting up python3-minimal (3.13.1-2) ...
Selecting previously unselected package python3.
(Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 21173 files and directories currently installed.)
Preparing to unpack .../000-python3_3.13.1-2_i386.deb ...
Unpacking python3 (3.13.1-2) ...
Selecting previously unselected package libpython3.12-minimal:i386.
Preparing to unpack .../001-libpython3.12-minimal_3.12.8-5_i386.deb ...
Unpacking libpython3.12-minimal:i386 (3.12.8-5) ...
Selecting previously unselected package python3.12-minimal.
Preparing to unpack .../002-python3.12-minimal_3.12.8-5_i386.deb ...
Unpacking python3.12-minimal (3.12.8-5) ...
Selecting previously unselected package sensible-utils.
Preparing to unpack .../003-sensible-utils_0.0.24_all.deb ...
Unpacking sensible-utils (0.0.24) ...
Selecting previously unselected package openssl.
Preparing to unpack .../004-openssl_3.4.0-2_i386.deb ...
Unpacking openssl (3.4.0-2) ...
Selecting previously unselected package ca-certificates.
Preparing to unpack .../005-ca-certificates_20241223_all.deb ...
Unpacking ca-certificates (20241223) ...
Selecting previously unselected package libmagic-mgc.
Preparing to unpack .../006-libmagic-mgc_1%3a5.45-3+b1_i386.deb ...
Unpacking libmagic-mgc (1:5.45-3+b1) ...
Selecting previously unselected package libmagic1t64:i386.
Preparing to unpack .../007-libmagic1t64_1%3a5.45-3+b1_i386.deb ...
Unpacking libmagic1t64:i386 (1:5.45-3+b1) ...
Selecting previously unselected package file.
Preparing to unpack .../008-file_1%3a5.45-3+b1_i386.deb ...
Unpacking file (1:5.45-3+b1) ...
Selecting previously unselected package gettext-base.
Preparing to unpack .../009-gettext-base_0.23.1-1_i386.deb ...
Unpacking gettext-base (0.23.1-1) ...
Selecting previously unselected package libuchardet0:i386.
Preparing to unpack .../010-libuchardet0_0.0.8-1+b2_i386.deb ...
Unpacking libuchardet0:i386 (0.0.8-1+b2) ...
Selecting previously unselected package groff-base.
Preparing to unpack .../011-groff-base_1.23.0-7_i386.deb ...
Unpacking groff-base (1.23.0-7) ...
Selecting previously unselected package locales.
Preparing to unpack .../012-locales_2.40-6_all.deb ...
Unpacking locales (2.40-6) ...
Selecting previously unselected package bsdextrautils.
Preparing to unpack .../013-bsdextrautils_2.40.4-2_i386.deb ...
Unpacking bsdextrautils (2.40.4-2) ...
Selecting previously unselected package libpipeline1:i386.
Preparing to unpack .../014-libpipeline1_1.5.8-1_i386.deb ...
Unpacking libpipeline1:i386 (1.5.8-1) ...
Selecting previously unselected package man-db.
Preparing to unpack .../015-man-db_2.13.0-1_i386.deb ...
Unpacking man-db (2.13.0-1) ...
Selecting previously unselected package m4.
Preparing to unpack .../016-m4_1.4.19-5_i386.deb ...
Unpacking m4 (1.4.19-5) ...
Selecting previously unselected package autoconf.
Preparing to unpack .../017-autoconf_2.72-3_all.deb ...
Unpacking autoconf (2.72-3) ...
Selecting previously unselected package autotools-dev.
Preparing to unpack .../018-autotools-dev_20220109.1_all.deb ...
Unpacking autotools-dev (20220109.1) ...
Selecting previously unselected package automake.
Preparing to unpack .../019-automake_1%3a1.17-2_all.deb ...
Unpacking automake (1:1.17-2) ...
Selecting previously unselected package autopoint.
Preparing to unpack .../020-autopoint_0.23.1-1_all.deb ...
Unpacking autopoint (0.23.1-1) ...
Selecting previously unselected package libdebhelper-perl.
Preparing to unpack .../021-libdebhelper-perl_13.24.1_all.deb ...
Unpacking libdebhelper-perl (13.24.1) ...
Selecting previously unselected package libtool.
Preparing to unpack .../022-libtool_2.5.4-2_all.deb ...
Unpacking libtool (2.5.4-2) ...
Selecting previously unselected package dh-autoreconf.
Preparing to unpack .../023-dh-autoreconf_20_all.deb ...
Unpacking dh-autoreconf (20) ...
Selecting previously unselected package libarchive-zip-perl.
Preparing to unpack .../024-libarchive-zip-perl_1.68-1_all.deb ...
Unpacking libarchive-zip-perl (1.68-1) ...
Selecting previously unselected package libfile-stripnondeterminism-perl.
Preparing to unpack .../025-libfile-stripnondeterminism-perl_1.14.1-1_all.deb ...
Unpacking libfile-stripnondeterminism-perl (1.14.1-1) ...
Selecting previously unselected package dh-strip-nondeterminism.
Preparing to unpack .../026-dh-strip-nondeterminism_1.14.1-1_all.deb ...
Unpacking dh-strip-nondeterminism (1.14.1-1) ...
Selecting previously unselected package libelf1t64:i386.
Preparing to unpack .../027-libelf1t64_0.192-4_i386.deb ...
Unpacking libelf1t64:i386 (0.192-4) ...
Selecting previously unselected package dwz.
Preparing to unpack .../028-dwz_0.15-1+b1_i386.deb ...
Unpacking dwz (0.15-1+b1) ...
Selecting previously unselected package libunistring5:i386.
Preparing to unpack .../029-libunistring5_1.3-1_i386.deb ...
Unpacking libunistring5:i386 (1.3-1) ...
Selecting previously unselected package libicu72:i386.
Preparing to unpack .../030-libicu72_72.1-6_i386.deb ...
Unpacking libicu72:i386 (72.1-6) ...
Selecting previously unselected package libxml2:i386.
Preparing to unpack .../031-libxml2_2.12.7+dfsg+really2.9.14-0.2+b1_i386.deb ...
Unpacking libxml2:i386 (2.12.7+dfsg+really2.9.14-0.2+b1) ...
Selecting previously unselected package gettext.
Preparing to unpack .../032-gettext_0.23.1-1_i386.deb ...
Unpacking gettext (0.23.1-1) ...
Selecting previously unselected package intltool-debian.
Preparing to unpack .../033-intltool-debian_0.35.0+20060710.6_all.deb ...
Unpacking intltool-debian (0.35.0+20060710.6) ...
Selecting previously unselected package po-debconf.
Preparing to unpack .../034-po-debconf_1.0.21+nmu1_all.deb ...
Unpacking po-debconf (1.0.21+nmu1) ...
Selecting previously unselected package debhelper.
Preparing to unpack .../035-debhelper_13.24.1_all.deb ...
Unpacking debhelper (13.24.1) ...
Selecting previously unselected package python3-autocommand.
Preparing to unpack .../036-python3-autocommand_2.2.2-3_all.deb ...
Unpacking python3-autocommand (2.2.2-3) ...
Selecting previously unselected package python3-more-itertools.
Preparing to unpack .../037-python3-more-itertools_10.6.0-1_all.deb ...
Unpacking python3-more-itertools (10.6.0-1) ...
Selecting previously unselected package python3-typing-extensions.
Preparing to unpack .../038-python3-typing-extensions_4.12.2-2_all.deb ...
Unpacking python3-typing-extensions (4.12.2-2) ...
Selecting previously unselected package python3-typeguard.
Preparing to unpack .../039-python3-typeguard_4.4.1-1_all.deb ...
Unpacking python3-typeguard (4.4.1-1) ...
Selecting previously unselected package python3-inflect.
Preparing to unpack .../040-python3-inflect_7.3.1-2_all.deb ...
Unpacking python3-inflect (7.3.1-2) ...
Selecting previously unselected package python3-jaraco.context.
Preparing to unpack .../041-python3-jaraco.context_6.0.0-1_all.deb ...
Unpacking python3-jaraco.context (6.0.0-1) ...
Selecting previously unselected package python3-jaraco.functools.
Preparing to unpack .../042-python3-jaraco.functools_4.1.0-1_all.deb ...
Unpacking python3-jaraco.functools (4.1.0-1) ...
Selecting previously unselected package python3-pkg-resources.
Preparing to unpack .../043-python3-pkg-resources_75.6.0-1_all.deb ...
Unpacking python3-pkg-resources (75.6.0-1) ...
Selecting previously unselected package python3-jaraco.text.
Preparing to unpack .../044-python3-jaraco.text_4.0.0-1_all.deb ...
Unpacking python3-jaraco.text (4.0.0-1) ...
Selecting previously unselected package python3-zipp.
Preparing to unpack .../045-python3-zipp_3.21.0-1_all.deb ...
Unpacking python3-zipp (3.21.0-1) ...
Selecting previously unselected package python3-setuptools.
Preparing to unpack .../046-python3-setuptools_75.6.0-1_all.deb ...
Unpacking python3-setuptools (75.6.0-1) ...
Selecting previously unselected package dh-python.
Preparing to unpack .../047-dh-python_6.20250108_all.deb ...
Unpacking dh-python (6.20250108) ...
Selecting previously unselected package libbrotli1:i386.
Preparing to unpack .../048-libbrotli1_1.1.0-2+b6_i386.deb ...
Unpacking libbrotli1:i386 (1.1.0-2+b6) ...
Selecting previously unselected package libidn2-0:i386.
Preparing to unpack .../049-libidn2-0_2.3.7-2+b1_i386.deb ...
Unpacking libidn2-0:i386 (2.3.7-2+b1) ...
Selecting previously unselected package libp11-kit0:i386.
Preparing to unpack .../050-libp11-kit0_0.25.5-3_i386.deb ...
Unpacking libp11-kit0:i386 (0.25.5-3) ...
Selecting previously unselected package libtasn1-6:i386.
Preparing to unpack .../051-libtasn1-6_4.19.0-3+b3_i386.deb ...
Unpacking libtasn1-6:i386 (4.19.0-3+b3) ...
Selecting previously unselected package libgnutls30t64:i386.
Preparing to unpack .../052-libgnutls30t64_3.8.8-2_i386.deb ...
Unpacking libgnutls30t64:i386 (3.8.8-2) ...
Selecting previously unselected package libkrb5support0:i386.
Preparing to unpack .../053-libkrb5support0_1.21.3-4_i386.deb ...
Unpacking libkrb5support0:i386 (1.21.3-4) ...
Selecting previously unselected package libcom-err2:i386.
Preparing to unpack .../054-libcom-err2_1.47.2-1_i386.deb ...
Unpacking libcom-err2:i386 (1.47.2-1) ...
Selecting previously unselected package libk5crypto3:i386.
Preparing to unpack .../055-libk5crypto3_1.21.3-4_i386.deb ...
Unpacking libk5crypto3:i386 (1.21.3-4) ...
Selecting previously unselected package libkeyutils1:i386.
Preparing to unpack .../056-libkeyutils1_1.6.3-4_i386.deb ...
Unpacking libkeyutils1:i386 (1.6.3-4) ...
Selecting previously unselected package libkrb5-3:i386.
Preparing to unpack .../057-libkrb5-3_1.21.3-4_i386.deb ...
Unpacking libkrb5-3:i386 (1.21.3-4) ...
Selecting previously unselected package libgssapi-krb5-2:i386.
Preparing to unpack .../058-libgssapi-krb5-2_1.21.3-4_i386.deb ...
Unpacking libgssapi-krb5-2:i386 (1.21.3-4) ...
Selecting previously unselected package libsasl2-modules-db:i386.
Preparing to unpack .../059-libsasl2-modules-db_2.1.28+dfsg1-8+b1_i386.deb ...
Unpacking libsasl2-modules-db:i386 (2.1.28+dfsg1-8+b1) ...
Selecting previously unselected package libsasl2-2:i386.
Preparing to unpack .../060-libsasl2-2_2.1.28+dfsg1-8+b1_i386.deb ...
Unpacking libsasl2-2:i386 (2.1.28+dfsg1-8+b1) ...
Selecting previously unselected package libldap2:i386.
Preparing to unpack .../061-libldap2_2.6.9+dfsg-1_i386.deb ...
Unpacking libldap2:i386 (2.6.9+dfsg-1) ...
Selecting previously unselected package libnghttp2-14:i386.
Preparing to unpack .../062-libnghttp2-14_1.64.0-1_i386.deb ...
Unpacking libnghttp2-14:i386 (1.64.0-1) ...
Selecting previously unselected package libnghttp3-9:i386.
Preparing to unpack .../063-libnghttp3-9_1.6.0-2_i386.deb ...
Unpacking libnghttp3-9:i386 (1.6.0-2) ...
Selecting previously unselected package libngtcp2-16:i386.
Preparing to unpack .../064-libngtcp2-16_1.9.1-1_i386.deb ...
Unpacking libngtcp2-16:i386 (1.9.1-1) ...
Selecting previously unselected package libngtcp2-crypto-gnutls8:i386.
Preparing to unpack .../065-libngtcp2-crypto-gnutls8_1.9.1-1_i386.deb ...
Unpacking libngtcp2-crypto-gnutls8:i386 (1.9.1-1) ...
Selecting previously unselected package libpsl5t64:i386.
Preparing to unpack .../066-libpsl5t64_0.21.2-1.1+b1_i386.deb ...
Unpacking libpsl5t64:i386 (0.21.2-1.1+b1) ...
Selecting previously unselected package librtmp1:i386.
Preparing to unpack .../067-librtmp1_2.4+20151223.gitfa8646d.1-2+b5_i386.deb ...
Unpacking librtmp1:i386 (2.4+20151223.gitfa8646d.1-2+b5) ...
Selecting previously unselected package libssh2-1t64:i386.
Preparing to unpack .../068-libssh2-1t64_1.11.1-1_i386.deb ...
Unpacking libssh2-1t64:i386 (1.11.1-1) ...
Selecting previously unselected package libcurl3t64-gnutls:i386.
Preparing to unpack .../069-libcurl3t64-gnutls_8.11.1-1+b1_i386.deb ...
Unpacking libcurl3t64-gnutls:i386 (8.11.1-1+b1) ...
Selecting previously unselected package liberror-perl.
Preparing to unpack .../070-liberror-perl_0.17029-2_all.deb ...
Unpacking liberror-perl (0.17029-2) ...
Selecting previously unselected package git-man.
Preparing to unpack .../071-git-man_1%3a2.47.2-0.1_all.deb ...
Unpacking git-man (1:2.47.2-0.1) ...
Selecting previously unselected package git.
Preparing to unpack .../072-git_1%3a2.47.2-0.1_i386.deb ...
Unpacking git (1:2.47.2-0.1) ...
Selecting previously unselected package libtirpc-common.
Preparing to unpack .../073-libtirpc-common_1.3.4+ds-1.3_all.deb ...
Unpacking libtirpc-common (1.3.4+ds-1.3) ...
Selecting previously unselected package libtirpc3t64:i386.
Preparing to unpack .../074-libtirpc3t64_1.3.4+ds-1.3+b1_i386.deb ...
Adding 'diversion of /lib/i386-linux-gnu/libtirpc.so.3 to /lib/i386-linux-gnu/libtirpc.so.3.usr-is-merged by libtirpc3t64'
Adding 'diversion of /lib/i386-linux-gnu/libtirpc.so.3.0.0 to /lib/i386-linux-gnu/libtirpc.so.3.0.0.usr-is-merged by libtirpc3t64'
Unpacking libtirpc3t64:i386 (1.3.4+ds-1.3+b1) ...
Selecting previously unselected package libnsl2:i386.
Preparing to unpack .../075-libnsl2_1.3.0-3+b3_i386.deb ...
Unpacking libnsl2:i386 (1.3.0-3+b3) ...
Selecting previously unselected package libpython3.12-stdlib:i386.
Preparing to unpack .../076-libpython3.12-stdlib_3.12.8-5_i386.deb ...
Unpacking libpython3.12-stdlib:i386 (3.12.8-5) ...
Selecting previously unselected package localehelper.
Preparing to unpack .../077-localehelper_0.1.4-3.1_all.deb ...
Unpacking localehelper (0.1.4-3.1) ...
Selecting previously unselected package python3.12.
Preparing to unpack .../078-python3.12_3.12.8-5_i386.deb ...
Unpacking python3.12 (3.12.8-5) ...
Selecting previously unselected package python3-all.
Preparing to unpack .../079-python3-all_3.13.1-2_i386.deb ...
Unpacking python3-all (3.13.1-2) ...
Selecting previously unselected package python3-ansi.
Preparing to unpack .../080-python3-ansi_0.1.5-2_all.deb ...
Unpacking python3-ansi (0.1.5-2) ...
Selecting previously unselected package python3-bcrypt.
Preparing to unpack .../081-python3-bcrypt_4.2.0-2.1_i386.deb ...
Unpacking python3-bcrypt (4.2.0-2.1) ...
Selecting previously unselected package python3-blinker.
Preparing to unpack .../082-python3-blinker_1.9.0-1_all.deb ...
Unpacking python3-blinker (1.9.0-1) ...
Selecting previously unselected package python3-bottle.
Preparing to unpack .../083-python3-bottle_0.13.2-1.1_all.deb ...
Unpacking python3-bottle (0.13.2-1.1) ...
Selecting previously unselected package python3-soupsieve.
Preparing to unpack .../084-python3-soupsieve_2.6-1_all.deb ...
Unpacking python3-soupsieve (2.6-1) ...
Selecting previously unselected package python3-bs4.
Preparing to unpack .../085-python3-bs4_4.12.3-3_all.deb ...
Unpacking python3-bs4 (4.12.3-3) ...
Selecting previously unselected package python3-certifi.
Preparing to unpack .../086-python3-certifi_2024.12.14+ds-1_all.deb ...
Unpacking python3-certifi (2024.12.14+ds-1) ...
Selecting previously unselected package python3-cffi-backend:i386.
Preparing to unpack .../087-python3-cffi-backend_1.17.1-2+b1_i386.deb ...
Unpacking python3-cffi-backend:i386 (1.17.1-2+b1) ...
Selecting previously unselected package python3-chardet.
Preparing to unpack .../088-python3-chardet_5.2.0+dfsg-2_all.deb ...
Unpacking python3-chardet (5.2.0+dfsg-2) ...
Selecting previously unselected package python3-charset-normalizer.
Preparing to unpack .../089-python3-charset-normalizer_3.4.0-1+b1_i386.deb ...
Unpacking python3-charset-normalizer (3.4.0-1+b1) ...
Selecting previously unselected package python3-click.
Preparing to unpack .../090-python3-click_8.1.8-1_all.deb ...
Unpacking python3-click (8.1.8-1) ...
Selecting previously unselected package python3-colorlog.
Preparing to unpack .../091-python3-colorlog_6.9.0-1_all.deb ...
Unpacking python3-colorlog (6.9.0-1) ...
Selecting previously unselected package python3-cryptography.
Preparing to unpack .../092-python3-cryptography_43.0.0-1_i386.deb ...
Unpacking python3-cryptography (43.0.0-1) ...
Selecting previously unselected package python3-daemonize.
Preparing to unpack .../093-python3-daemonize_2.5.0-3_all.deb ...
Unpacking python3-daemonize (2.5.0-3) ...
Selecting previously unselected package python3-urllib3.
Preparing to unpack .../094-python3-urllib3_2.3.0-1_all.deb ...
Unpacking python3-urllib3 (2.3.0-1) ...
Selecting previously unselected package python3-dulwich.
Preparing to unpack .../095-python3-dulwich_0.22.7-1_i386.deb ...
Unpacking python3-dulwich (0.22.7-1) ...
Selecting previously unselected package python3-itsdangerous.
Preparing to unpack .../096-python3-itsdangerous_2.2.0-2_all.deb ...
Unpacking python3-itsdangerous (2.2.0-2) ...
Selecting previously unselected package python3-markupsafe.
Preparing to unpack .../097-python3-markupsafe_2.1.5-1+b2_i386.deb ...
Unpacking python3-markupsafe (2.1.5-1+b2) ...
Selecting previously unselected package python3-jinja2.
Preparing to unpack .../098-python3-jinja2_3.1.5-1_all.deb ...
Unpacking python3-jinja2 (3.1.5-1) ...
Selecting previously unselected package python3-werkzeug.
Preparing to unpack .../099-python3-werkzeug_3.1.3-2_all.deb ...
Unpacking python3-werkzeug (3.1.3-2) ...
Selecting previously unselected package python3-flask.
Preparing to unpack .../100-python3-flask_3.1.0-2_all.deb ...
Unpacking python3-flask (3.1.0-2) ...
Selecting previously unselected package python3-idna.
Preparing to unpack .../101-python3-idna_3.8-2_all.deb ...
Unpacking python3-idna (3.8-2) ...
Selecting previously unselected package python3-iniconfig.
Preparing to unpack .../102-python3-iniconfig_1.1.1-2_all.deb ...
Unpacking python3-iniconfig (1.1.1-2) ...
Selecting previously unselected package python3-legacy-cgi.
Preparing to unpack .../103-python3-legacy-cgi_2.6.1-2_all.deb ...
Unpacking python3-legacy-cgi (2.6.1-2) ...
Selecting previously unselected package python3-markdown.
Preparing to unpack .../104-python3-markdown_3.7-2_all.deb ...
Unpacking python3-markdown (3.7-2) ...
Selecting previously unselected package python3-openssl.
Preparing to unpack .../105-python3-openssl_25.0.0-1_all.deb ...
Unpacking python3-openssl (25.0.0-1) ...
Selecting previously unselected package python3-packaging.
Preparing to unpack .../106-python3-packaging_24.2-1_all.deb ...
Unpacking python3-packaging (24.2-1) ...
Selecting previously unselected package python3-tempita.
Preparing to unpack .../107-python3-tempita_0.6.0-1_all.deb ...
Unpacking python3-tempita (0.6.0-1) ...
Selecting previously unselected package python3-paste.
Preparing to unpack .../108-python3-paste_3.10.1-1_all.deb ...
Unpacking python3-paste (3.10.1-1) ...
Selecting previously unselected package python3-pastedeploy-tpl.
Preparing to unpack .../109-python3-pastedeploy-tpl_3.1-1_all.deb ...
Unpacking python3-pastedeploy-tpl (3.1-1) ...
Selecting previously unselected package python3-pastedeploy.
Preparing to unpack .../110-python3-pastedeploy_3.1-1_all.deb ...
Unpacking python3-pastedeploy (3.1-1) ...
Selecting previously unselected package python3-pluggy.
Preparing to unpack .../111-python3-pluggy_1.5.0-1_all.deb ...
Unpacking python3-pluggy (1.5.0-1) ...
Selecting previously unselected package python3-pygments.
Preparing to unpack .../112-python3-pygments_2.18.0+dfsg-2_all.deb ...
Unpacking python3-pygments (2.18.0+dfsg-2) ...
Selecting previously unselected package python3-pytest.
Preparing to unpack .../113-python3-pytest_8.3.4-1_all.deb ...
Unpacking python3-pytest (8.3.4-1) ...
Selecting previously unselected package python3-requests.
Preparing to unpack .../114-python3-requests_2.32.3+dfsg-1_all.deb ...
Unpacking python3-requests (2.32.3+dfsg-1) ...
Selecting previously unselected package python3-waitress.
Preparing to unpack .../115-python3-waitress_3.0.2-1_all.deb ...
Unpacking python3-waitress (3.0.2-1) ...
Selecting previously unselected package python3-webob.
Preparing to unpack .../116-python3-webob_1%3a1.8.9-1_all.deb ...
Unpacking python3-webob (1:1.8.9-1) ...
Selecting previously unselected package python3-webtest.
Preparing to unpack .../117-python3-webtest_3.0.2-1_all.deb ...
Unpacking python3-webtest (3.0.2-1) ...
Selecting previously unselected package python3-yapsy.
Preparing to unpack .../118-python3-yapsy_1.12.2-3_all.deb ...
Unpacking python3-yapsy (1.12.2-3) ...
Setting up media-types (10.1.0) ...
Setting up libpipeline1:i386 (1.5.8-1) ...
Setting up libkeyutils1:i386 (1.6.3-4) ...
Setting up libicu72:i386 (72.1-6) ...
Setting up bsdextrautils (2.40.4-2) ...
Setting up libmagic-mgc (1:5.45-3+b1) ...
Setting up libarchive-zip-perl (1.68-1) ...
Setting up libtirpc-common (1.3.4+ds-1.3) ...
Setting up libdebhelper-perl (13.24.1) ...
Setting up libbrotli1:i386 (1.1.0-2+b6) ...
Setting up libmagic1t64:i386 (1:5.45-3+b1) ...
Setting up libpython3.12-minimal:i386 (3.12.8-5) ...
Setting up libnghttp2-14:i386 (1.64.0-1) ...
Setting up gettext-base (0.23.1-1) ...
Setting up m4 (1.4.19-5) ...
Setting up libcom-err2:i386 (1.47.2-1) ...
Setting up file (1:5.45-3+b1) ...
Setting up locales (2.40-6) ...
locales-all installed, skipping locales generation
Setting up libelf1t64:i386 (0.192-4) ...
Setting up libkrb5support0:i386 (1.21.3-4) ...
Setting up libsasl2-modules-db:i386 (2.1.28+dfsg1-8+b1) ...
Setting up tzdata (2025a-1) ...

Current default time zone: 'Etc/UTC'
Local time is now:      Tue Jan 28 14:59:03 UTC 2025.
Universal Time is now:  Tue Jan 28 14:59:03 UTC 2025.
Run 'dpkg-reconfigure tzdata' if you wish to change it.

Setting up liberror-perl (0.17029-2) ...
Setting up autotools-dev (20220109.1) ...
Setting up localehelper (0.1.4-3.1) ...
Setting up python3-pastedeploy-tpl (3.1-1) ...
Setting up libunistring5:i386 (1.3-1) ...
Setting up autopoint (0.23.1-1) ...
Setting up libk5crypto3:i386 (1.21.3-4) ...
Setting up libsasl2-2:i386 (2.1.28+dfsg1-8+b1) ...
Setting up autoconf (2.72-3) ...
Setting up libnghttp3-9:i386 (1.6.0-2) ...
Setting up libffi8:i386 (3.4.6-1) ...
Setting up dwz (0.15-1+b1) ...
Setting up sensible-utils (0.0.24) ...
Setting up libuchardet0:i386 (0.0.8-1+b2) ...
Setting up libtasn1-6:i386 (4.19.0-3+b3) ...
Setting up git-man (1:2.47.2-0.1) ...
Setting up netbase (6.4) ...
Setting up libngtcp2-16:i386 (1.9.1-1) ...
Setting up libkrb5-3:i386 (1.21.3-4) ...
Setting up libssh2-1t64:i386 (1.11.1-1) ...
Setting up openssl (3.4.0-2) ...
Setting up readline-common (8.2-6) ...
Setting up libxml2:i386 (2.12.7+dfsg+really2.9.14-0.2+b1) ...
Setting up libldap2:i386 (2.6.9+dfsg-1) ...
Setting up automake (1:1.17-2) ...
update-alternatives: using /usr/bin/automake-1.17 to provide /usr/bin/automake (automake) in auto mode
Setting up libfile-stripnondeterminism-perl (1.14.1-1) ...
Setting up python3.12-minimal (3.12.8-5) ...
Setting up gettext (0.23.1-1) ...
Setting up libtool (2.5.4-2) ...
Setting up libidn2-0:i386 (2.3.7-2+b1) ...
Setting up intltool-debian (0.35.0+20060710.6) ...
Setting up dh-autoreconf (20) ...
Setting up ca-certificates (20241223) ...
Updating certificates in /etc/ssl/certs...
152 added, 0 removed; done.
Setting up libp11-kit0:i386 (0.25.5-3) ...
Setting up libgssapi-krb5-2:i386 (1.21.3-4) ...
Setting up libreadline8t64:i386 (8.2-6) ...
Setting up dh-strip-nondeterminism (1.14.1-1) ...
Setting up groff-base (1.23.0-7) ...
Setting up libpython3.13-stdlib:i386 (3.13.1-3) ...
Setting up libpython3-stdlib:i386 (3.13.1-2) ...
Setting up libgnutls30t64:i386 (3.8.8-2) ...
Setting up libtirpc3t64:i386 (1.3.4+ds-1.3+b1) ...
Setting up python3.13 (3.13.1-3) ...
Setting up po-debconf (1.0.21+nmu1) ...
Setting up libpsl5t64:i386 (0.21.2-1.1+b1) ...
Setting up python3 (3.13.1-2) ...
Setting up python3-zipp (3.21.0-1) ...
Setting up python3-click (8.1.8-1) ...
Setting up python3-autocommand (2.2.2-3) ...
Setting up man-db (2.13.0-1) ...
Not building database; man-db/auto-update is not 'true'.
Setting up python3-markupsafe (2.1.5-1+b2) ...
Setting up python3-jinja2 (3.1.5-1) ...
Setting up python3-pygments (2.18.0+dfsg-2) ...
Setting up python3-tempita (0.6.0-1) ...
Setting up python3-packaging (24.2-1) ...
Setting up python3-ansi (0.1.5-2) ...
Setting up python3-chardet (5.2.0+dfsg-2) ...
Setting up python3-certifi (2024.12.14+ds-1) ...
Setting up librtmp1:i386 (2.4+20151223.gitfa8646d.1-2+b5) ...
Setting up python3-werkzeug (3.1.3-2) ...
Setting up python3-idna (3.8-2) ...
Setting up python3-markdown (3.7-2) ...
Setting up python3-typing-extensions (4.12.2-2) ...
Setting up python3-urllib3 (2.3.0-1) ...
Setting up python3-pluggy (1.5.0-1) ...
Setting up python3-legacy-cgi (2.6.1-2) ...
Setting up python3-dulwich (0.22.7-1) ...
Setting up libnsl2:i386 (1.3.0-3+b3) ...
Setting up python3-soupsieve (2.6-1) ...
Setting up libngtcp2-crypto-gnutls8:i386 (1.9.1-1) ...
Setting up python3-cffi-backend:i386 (1.17.1-2+b1) ...
Setting up python3-webob (1:1.8.9-1) ...
Setting up python3-yapsy (1.12.2-3) ...
Setting up python3-blinker (1.9.0-1) ...
Setting up python3-daemonize (2.5.0-3) ...
Setting up python3-more-itertools (10.6.0-1) ...
Setting up python3-iniconfig (1.1.1-2) ...
Setting up python3-waitress (3.0.2-1) ...
Setting up python3-jaraco.functools (4.1.0-1) ...
Setting up libpython3.12-stdlib:i386 (3.12.8-5) ...
Setting up python3-bottle (0.13.2-1.1) ...
Setting up python3-jaraco.context (6.0.0-1) ...
Setting up python3-colorlog (6.9.0-1) ...
Setting up python3-charset-normalizer (3.4.0-1+b1) ...
Setting up python3-pytest (8.3.4-1) ...
Setting up python3-bcrypt (4.2.0-2.1) ...
Setting up python3.12 (3.12.8-5) ...
Setting up python3-typeguard (4.4.1-1) ...
Setting up libcurl3t64-gnutls:i386 (8.11.1-1+b1) ...
Setting up python3-itsdangerous (2.2.0-2) ...
Setting up python3-all (3.13.1-2) ...
Setting up debhelper (13.24.1) ...
Setting up python3-bs4 (4.12.3-3) ...
Setting up python3-inflect (7.3.1-2) ...
Setting up python3-jaraco.text (4.0.0-1) ...
Setting up python3-cryptography (43.0.0-1) ...
Setting up python3-requests (2.32.3+dfsg-1) ...
Setting up git (1:2.47.2-0.1) ...
Setting up python3-pkg-resources (75.6.0-1) ...
Setting up python3-setuptools (75.6.0-1) ...
Setting up python3-openssl (25.0.0-1) ...
Setting up python3-flask (3.1.0-2) ...
Setting up python3-paste (3.10.1-1) ...
Setting up dh-python (6.20250108) ...
Setting up python3-pastedeploy (3.1-1) ...
Setting up python3-webtest (3.0.2-1) ...
Processing triggers for libc-bin (2.40-6) ...
Processing triggers for ca-certificates (20241223) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
Reading package lists...
Building dependency tree...
Reading state information...
Reading extended state information...
Initializing package states...
Writing extended state information...
Building tag database...
 -> Finished parsing the build-deps
I: Building the package
I: Running cd /build/reproducible-path/errbot-6.2.0+ds/ && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" HOME="/nonexistent/first-build" dpkg-buildpackage -us -uc -b && env PATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" HOME="/nonexistent/first-build" dpkg-genchanges -S  > ../errbot_6.2.0+ds-4_source.changes
dpkg-buildpackage: info: source package errbot
dpkg-buildpackage: info: source version 6.2.0+ds-4
dpkg-buildpackage: info: source distribution unstable
dpkg-buildpackage: info: source changed by Alexandre Detiste <tchet@debian.org>
 dpkg-source --before-build .
dpkg-buildpackage: info: host architecture i386
 debian/rules clean
dh clean --buildsystem=pybuild
   dh_auto_clean -O--buildsystem=pybuild
	pybuild --clean -i python{version} -p "3.12 3.13"
I: pybuild base:311: python3.12 setup.py clean 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running clean
removing '/build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build' (and everything under it)
'build/bdist.linux-i686' does not exist -- can't clean it
'build/scripts-3.12' does not exist -- can't clean it
I: pybuild base:311: python3.13 setup.py clean 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running clean
removing '/build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build' (and everything under it)
'build/bdist.linux-i686' does not exist -- can't clean it
'build/scripts-3.13' does not exist -- can't clean it
	rm -rf .pybuild/
	find . -name \*.pyc -exec rm {} \;
   dh_autoreconf_clean -O--buildsystem=pybuild
   dh_clean -O--buildsystem=pybuild
	rm -f debian/debhelper-build-stamp
	rm -rf debian/.debhelper/
	rm -f -- debian/errbot.substvars debian/files
	rm -fr -- debian/errbot/ debian/tmp/
	find .  \( \( \
		\( -path .\*/.git -o -path .\*/.svn -o -path .\*/.bzr -o -path .\*/.hg -o -path .\*/CVS -o -path .\*/.pc -o -path .\*/_darcs \) -prune -o -type f -a \
	        \( -name '#*#' -o -name '.*~' -o -name '*~' -o -name DEADJOE \
		 -o -name '*.orig' -o -name '*.rej' -o -name '*.bak' \
		 -o -name '.*.orig' -o -name .*.rej -o -name '.SUMS' \
		 -o -name TAGS -o \( -path '*/.deps/*' -a -name '*.P' \) \
		\) -exec rm -f {} + \) -o \
		\( -type d -a \( -name autom4te.cache -o -name __pycache__ \) -prune -exec rm -rf {} + \) \)
 debian/rules binary
dh binary --buildsystem=pybuild
   dh_update_autotools_config -O--buildsystem=pybuild
   dh_autoreconf -O--buildsystem=pybuild
   dh_auto_configure -O--buildsystem=pybuild
	pybuild --configure -i python{version} -p "3.12 3.13"
I: pybuild base:311: python3.12 setup.py config 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running config
I: pybuild base:311: python3.13 setup.py config 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running config
   dh_auto_build -O--buildsystem=pybuild
	pybuild --build -i python{version} -p "3.12 3.13"
I: pybuild base:311: /usr/bin/python3.12 setup.py build 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running build
running build_py
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/repo_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/bootstrap.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/plugin_info.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/streaming.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/botplugin.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/backend_plugin_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/logs.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/flow.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/templating.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/version.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/core.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/plugin_wizard.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/config-template.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/plugin_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/utils.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
copying ./errbot/cli.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/null.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/xmpp.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/base.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/test.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/text.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/irc.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/telegram_messenger.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/acls.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/backup.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/wsview.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/webserver.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/health.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/vcheck.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/cnf_filter.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/utils.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/chatRoom.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/help.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/textcmds.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/plugins.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/flows.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/rendering
copying ./errbot/rendering/ansiext.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/rendering
copying ./errbot/rendering/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/rendering
copying ./errbot/rendering/xhtmlim.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/rendering
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/storage/memory.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/storage/shelf.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/storage/base.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/storage/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/backends/null.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/test.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/text.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/irc.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/xmpp.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
copying ./errbot/backends/telegram_messenger.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/styles
copying ./errbot/backends/styles/style.css -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/styles
copying ./errbot/backends/styles/style-demo.css -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/styles
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/images
copying ./errbot/backends/images/errbot.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/images
copying ./errbot/backends/images/prompt.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/images
copying ./errbot/backends/images/errbot-bg.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/backends/images
copying ./errbot/core_plugins/chatRoom.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/help.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/utils.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/health.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/vcheck.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/flows.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/plugins.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/textcmds.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/cnf_filter.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/backup.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/webserver.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/acls.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/test.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_gc.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/about.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/webstatus.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/repos.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/plugin_info.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/webserver.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_plugins.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_load.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/repos2.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/core_plugins/templates
copying ./errbot/storage/shelf.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
copying ./errbot/storage/memory.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/storage
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/example.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/example.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/config.py.tmpl -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates/initdir
copying ./errbot/templates/card.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates
copying ./errbot/templates/new_plugin.py.tmpl -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build/errbot/templates
I: pybuild base:311: /usr/bin/python3 setup.py build 
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning: Unknown distribution option: 'tests_require'
  warnings.warn(msg)
running build
running build_py
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/repo_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/bootstrap.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/plugin_info.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/streaming.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/botplugin.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/backend_plugin_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/logs.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/flow.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/templating.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/version.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/core.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/plugin_wizard.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/config-template.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/plugin_manager.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/utils.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
copying ./errbot/cli.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/null.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/xmpp.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/base.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/test.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/text.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/irc.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/telegram_messenger.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/acls.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/backup.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/wsview.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/webserver.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/health.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/vcheck.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/cnf_filter.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/utils.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/chatRoom.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/help.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/textcmds.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/plugins.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/flows.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/rendering
copying ./errbot/rendering/ansiext.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/rendering
copying ./errbot/rendering/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/rendering
copying ./errbot/rendering/xhtmlim.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/rendering
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/storage/memory.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/storage/shelf.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/storage/base.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/storage/__init__.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/backends/null.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/test.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/text.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/irc.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/xmpp.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
copying ./errbot/backends/telegram_messenger.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/styles
copying ./errbot/backends/styles/style.css -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/styles
copying ./errbot/backends/styles/style-demo.css -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/styles
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/images
copying ./errbot/backends/images/errbot.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/images
copying ./errbot/backends/images/prompt.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/images
copying ./errbot/backends/images/errbot-bg.svg -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/backends/images
copying ./errbot/core_plugins/chatRoom.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/help.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/utils.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/health.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/vcheck.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/flows.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/plugins.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/textcmds.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/cnf_filter.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/backup.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/webserver.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/acls.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
copying ./errbot/core_plugins/test.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_gc.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/about.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/webstatus.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/repos.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/plugin_info.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/webserver.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_plugins.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/status_load.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/core_plugins/templates/repos2.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/core_plugins/templates
copying ./errbot/storage/shelf.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
copying ./errbot/storage/memory.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/storage
creating /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/example.py -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/example.plug -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates/initdir
copying ./errbot/templates/initdir/config.py.tmpl -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates/initdir
copying ./errbot/templates/card.md -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates
copying ./errbot/templates/new_plugin.py.tmpl -> /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build/errbot/templates
   debian/rules override_dh_auto_test
make[1]: Entering directory '/build/reproducible-path/errbot-6.2.0+ds'
localehelper LANG=en_US.UTF-8 dh_auto_test
	pybuild --test --test-pytest -i python{version} -p "3.12 3.13"
I: pybuild pybuild:308: rm -f /build/reproducible-path/errbot-6.2.0+ds/tests/backend_tests/slack_test.py
I: pybuild base:311: cd /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build; python3.12 -m pytest -k "not test_broken_plugin and not test_backup and not test_plugin_cycle and not test_entrypoint_paths and not test_check_dependencies_requirements_file_all_installed"
============================= test session starts ==============================
platform linux -- Python 3.12.8, pytest-8.3.4, pluggy-1.5.0
rootdir: /build/reproducible-path/errbot-6.2.0+ds
plugins: typeguard-4.4.1
collected 215 items / 8 deselected / 207 selected

tests/backend_manager_test.py ...                                        [  1%]
tests/backend_tests/text_test.py .                                       [  1%]
tests/base_backend_test.py .................................             [ 17%]
tests/cascade_dependencies_test.py .                                     [ 18%]
tests/circular_dependencies_test.py .                                    [ 18%]
tests/commands_test.py ........EEEEEEEEEEEEEEEEEEEE                      [ 32%]
tests/core_plugins_test.py EEE                                           [ 33%]
tests/core_test.py EE                                                    [ 34%]
tests/dependencies_test.py EEEEEEE                                       [ 38%]
tests/dynaplug_test.py EEEEE                                             [ 40%]
tests/flow_e2e_test.py EEEEEEEEEEEEE                                     [ 46%]
tests/flow_test.py ...                                                   [ 48%]
tests/i18n_test.py EEEE                                                  [ 50%]
tests/link_test.py E                                                     [ 50%]
tests/matchall_test.py EE                                                [ 51%]
tests/md_rendering_test.py ....                                          [ 53%]
tests/mention_test.py EEE                                                [ 55%]
tests/muc_test.py EEEEEE                                                 [ 57%]
tests/multi_plugin_test.py EE                                            [ 58%]
tests/persistence_test.py ..                                             [ 59%]
tests/plugin_config_fail_test.py E                                       [ 60%]
tests/plugin_config_test.py .......E                                     [ 64%]
tests/plugin_info_test.py ........                                       [ 68%]
tests/plugin_management_test.py .......                                  [ 71%]
tests/poller_test.py EE                                                  [ 72%]
tests/repo_manager_test.py .......                                       [ 75%]
tests/simple_identifiers_test.py .....                                   [ 78%]
tests/streaming_test.py F                                                [ 78%]
tests/syntax_test.py EEEE                                                [ 80%]
tests/templates_test.py EEEEE                                            [ 83%]
tests/utils_test.py ....................                                 [ 92%]
tests/webhooks_test.py EEEEEEEEEEEEEEE                                   [100%]

==================================== ERRORS ====================================
_________________________ ERROR at setup of test_echo __________________________

self = <multiprocessing.pool.ThreadPool state=INIT pool_size=2>, processes = 10
initializer = None, initargs = (), maxtasksperchild = None, context = None

    def __init__(self, processes=None, initializer=None, initargs=(),
                 maxtasksperchild=None, context=None):
        # Attributes initialized early to make sure that they exist in
        # __del__() if __init__() raises an exception
        self._pool = []
        self._state = INIT
    
        self._ctx = context or get_context()
        self._setup_queues()
        self._taskqueue = queue.SimpleQueue()
        # The _change_notifier queue exist to wake up self._handle_workers()
        # when the cache (self._cache) is empty or when there is a change in
        # the _state variable of the thread that runs _handle_workers.
        self._change_notifier = self._ctx.SimpleQueue()
        self._cache = _PoolCache(notifier=self._change_notifier)
        self._maxtasksperchild = maxtasksperchild
        self._initializer = initializer
        self._initargs = initargs
    
        if processes is None:
            processes = os.cpu_count() or 1
        if processes < 1:
            raise ValueError("Number of processes must be at least 1")
        if maxtasksperchild is not None:
            if not isinstance(maxtasksperchild, int) or maxtasksperchild <= 0:
                raise ValueError("maxtasksperchild must be a positive int or None")
    
        if initializer is not None and not callable(initializer):
            raise TypeError('initializer must be a callable')
    
        self._processes = processes
        try:
>           self._repopulate_pool()

/usr/lib/python3.12/multiprocessing/pool.py:215: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-498 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5d9d08>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <multiprocessing.pool.ThreadPool state=INIT pool_size=2>, processes = 10
initializer = None, initargs = (), maxtasksperchild = None, context = None

    def __init__(self, processes=None, initializer=None, initargs=(),
                 maxtasksperchild=None, context=None):
        # Attributes initialized early to make sure that they exist in
        # __del__() if __init__() raises an exception
        self._pool = []
        self._state = INIT
    
        self._ctx = context or get_context()
        self._setup_queues()
        self._taskqueue = queue.SimpleQueue()
        # The _change_notifier queue exist to wake up self._handle_workers()
        # when the cache (self._cache) is empty or when there is a change in
        # the _state variable of the thread that runs _handle_workers.
        self._change_notifier = self._ctx.SimpleQueue()
        self._cache = _PoolCache(notifier=self._change_notifier)
        self._maxtasksperchild = maxtasksperchild
        self._initializer = initializer
        self._initargs = initargs
    
        if processes is None:
            processes = os.cpu_count() or 1
        if processes < 1:
            raise ValueError("Number of processes must be at least 1")
        if maxtasksperchild is not None:
            if not isinstance(maxtasksperchild, int) or maxtasksperchild <= 0:
                raise ValueError("maxtasksperchild must be a positive int or None")
    
        if initializer is not None and not callable(initializer):
            raise TypeError('initializer must be a callable')
    
        self._processes = processes
        try:
            self._repopulate_pool()
        except Exception:
            for p in self._pool:
                if p.exitcode is None:
>                   p.terminate()
E                   AttributeError: 'DummyProcess' object has no attribute 'terminate'

/usr/lib/python3.12/multiprocessing/pool.py:219: AttributeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_echo>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5d9d08>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 219, in __init__
    p.terminate()
    ^^^^^^^^^^^
AttributeError: 'DummyProcess' object has no attribute 'terminate'
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:47,105 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:47,107 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:47,107 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:47,110 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:47,110 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:47,111 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 219, in __init__
    p.terminate()
    ^^^^^^^^^^^
AttributeError: 'DummyProcess' object has no attribute 'terminate'
_______________________ ERROR at setup of test_status_gc _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed34b288>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-499 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_status_gc>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed34b288>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:47,410 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:47,413 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:47,413 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:47,415 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:47,415 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:47,433 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_config_cycle ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeab23c00>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-500 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_config_cycle>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeab23c00>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:47,660 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:47,662 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:47,662 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:47,665 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:47,665 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:47,665 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_apropos ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea170618>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-501 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_apropos>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea170618>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:47,884 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:47,887 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:47,887 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:47,889 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:47,889 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:47,890 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_logtail ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174300>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-502 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_logtail>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174300>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:48,110 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:48,113 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:48,113 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:48,115 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:48,115 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:48,116 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_history ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea170af8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-503 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_history>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea170af8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:48,337 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:48,339 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:48,339 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:48,342 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:48,342 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:48,342 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________ ERROR at setup of test_encoding_preservation _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d5d210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-504 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_encoding_preservation>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d5d210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:48,563 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:48,566 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:48,566 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:48,568 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:48,569 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:48,569 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________ ERROR at setup of test_webserver_webhook_test _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1cacd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-505 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webserver_webhook_test>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1cacd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:48,794 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:48,797 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:48,797 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:48,799 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:48,799 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:48,800 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________ ERROR at setup of test_activate_reload_and_deactivate _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d5d720>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-506 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_activate_reload_and_deactivate>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d5d720>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:49,026 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:49,029 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:49,029 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:49,032 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:49,032 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:49,032 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________ ERROR at setup of test_unblacklist_and_blacklist _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea194c60>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-507 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_unblacklist_and_blacklist>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea194c60>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:49,252 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:49,254 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:49,255 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:49,257 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:49,257 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:49,258 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_optional_prefix ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea14df78>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-508 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_optional_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea14df78>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:49,545 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:49,547 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:49,548 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:49,550 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:49,550 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:49,551 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________ ERROR at setup of test_optional_prefix_re_cmd _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60cd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-509 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_optional_prefix_re_cmd>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60cd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:49,777 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:49,780 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:49,780 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:49,782 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:49,783 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:49,783 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_simple_match ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5de7b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-510 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_simple_match>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5de7b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:49,999 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:50,001 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:50,002 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:50,004 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:50,004 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:50,005 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________ ERROR at setup of test_no_suggest_on_re_commands _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebf807f8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-511 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_suggest_on_re_commands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebf807f8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:50,225 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:50,228 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:50,228 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:50,230 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:50,230 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:50,231 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_callback_no_command __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5de498>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-512 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_callback_no_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb5de498>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:50,450 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:50,453 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:50,453 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:50,455 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:50,456 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:50,456 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_subcommands ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebff15b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-513 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_subcommands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebff15b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:50,669 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:50,671 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:50,672 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:50,674 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:50,674 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:50,675 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______ ERROR at setup of test_command_not_found_with_space_in_bot_prefix _______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebfc9840>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-514 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_command_not_found_with_space_in_bot_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebfc9840>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:50,892 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:50,895 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:50,895 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:50,897 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:50,897 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:50,898 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_mock_injection _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebff1bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-515 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_mock_injection>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebff1bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:51,120 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:51,122 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:51,123 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:51,125 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:51,125 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:51,126 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_multiline_command ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec931210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-516 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_multiline_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec931210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:51,347 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:51,350 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:51,350 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:51,353 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:51,353 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:51,354 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_plugin_info_command __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed363840>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-517 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_info_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed363840>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:51,577 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:51,580 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:51,580 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:51,583 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:51,583 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:51,583 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_help_is_still_here ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed367ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-518 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_help_is_still_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed367ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:51,812 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:51,815 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:51,815 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:51,818 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:51,818 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:51,818 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_echo_still_here ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3955b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-519 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_echo_still_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3955b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:52,042 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:52,044 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:52,044 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:52,047 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:52,047 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:52,048 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_bot_prefix_replaced __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3ca078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-520 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_bot_prefix_replaced>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3ca078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:52,272 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:52,274 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:52,275 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:52,277 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:52,277 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:52,278 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_admins_to_notify ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed395bd0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-521 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_admins_to_notify>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed395bd0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'BOT_ADMINS_NOTIFICATIONS': 'zoni@localdomain'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:52,512 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:52,514 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:52,514 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:52,517 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:52,517 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:52,518 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_admins_not_notified __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeddb6a38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-522 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_admins_not_notified>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeddb6a38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'BOT_ADMINS_NOTIFICATIONS': 'zoni@localdomain'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:52,747 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:52,749 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:52,749 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:52,752 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:52,752 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:52,753 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________ ERROR at setup of test_if_all_loaded_by_default ________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd43e58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-523 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_if_all_loaded_by_default>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd43e58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:52,983 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:52,986 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:52,986 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:52,989 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:52,989 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:52,990 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_single_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd43210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-524 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_single_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd43210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:53,191 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:53,194 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:53,194 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:53,250 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:53,251 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:53,251 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_double_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1ca5b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-525 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_double_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1ca5b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:53,428 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:53,430 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:53,430 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:53,433 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:53,433 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:53,433 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________ ERROR at setup of test_dependency_retrieval __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf37551e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-526 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_dependency_retrieval>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf37551e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:53,599 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:53,601 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:53,602 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:53,604 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:53,604 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:53,604 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________ ERROR at setup of test_direct_circular_dependency _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebf6b0a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-527 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_direct_circular_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebf6b0a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:53,776 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:53,778 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:53,778 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:53,781 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:53,781 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:53,781 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________ ERROR at setup of test_indirect_circular_dependency ______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea14de40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-528 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_indirect_circular_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea14de40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:53,946 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:53,948 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:53,948 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:53,951 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:53,951 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:53,952 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_chained_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed363c60>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-529 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_chained_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed363c60>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,124 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,126 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,126 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,129 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,129 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:54,129 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_simple _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60e58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-530 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_simple>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60e58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,304 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,306 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,306 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,308 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,309 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:54,309 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_arg __________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3639c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-531 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_arg>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed3639c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,475 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,477 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,477 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,480 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,480 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:54,480 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_re ___________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea194660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-532 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_re>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea194660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,645 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,647 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,647 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,650 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,650 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:54,651 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_saw __________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe7994210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-533 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_saw>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe7994210>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,818 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,820 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,820 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,822 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,823 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:54,823 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_clashing ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe79945b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-534 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_clashing>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe79945b8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:54,994 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:54,996 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:54,996 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:54,999 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:54,999 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,000 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_list_flows _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83b4bd0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-535 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_list_flows>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83b4bd0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:55,208 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:55,211 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:55,211 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:55,213 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:55,213 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,214 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_no_autotrigger _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83e8120>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-536 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83e8120>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:55,387 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:55,390 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:55,390 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:55,393 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:55,393 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,394 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_autotrigger ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe979f468>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-537 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe979f468>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:55,564 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:55,566 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:55,566 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:55,569 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:55,569 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,570 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________ ERROR at setup of test_no_duplicate_autotrigger ________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe979f810>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-538 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_duplicate_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe979f810>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:55,739 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:55,741 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:55,741 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:55,744 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:55,744 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,745 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________ ERROR at setup of test_secondary_autotrigger _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83e4db0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-539 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_secondary_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe83e4db0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:55,982 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:55,984 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:55,984 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:55,987 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:55,987 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:55,988 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_manual_flow ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97a99f0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-540 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_manual_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97a99f0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:56,152 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:56,154 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:56,154 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:56,158 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:56,158 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:56,158 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________ ERROR at setup of test_manual_flow_with_or_without_hinting __________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97c4ff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-541 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_manual_flow_with_or_without_hinting>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97c4ff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:56,323 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:56,325 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:56,325 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:56,327 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:56,327 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:56,328 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________ ERROR at setup of test_no_flyby_trigger_flow _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf60f8c78>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-542 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_flyby_trigger_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf60f8c78>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:56,493 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:56,495 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:56,495 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:56,498 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:56,498 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:56,498 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_flow_only _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe79940a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-543 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flow_only>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe79940a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:56,669 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:56,671 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:56,671 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:56,674 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:56,674 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:56,674 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_flow_only_help _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9770cd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-544 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flow_only_help>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9770cd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:56,855 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:56,858 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:56,858 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:56,862 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:56,862 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:56,863 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_flows_stop _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65930a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-545 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flows_stop>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65930a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:57,087 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:57,090 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:57,090 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:57,093 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:57,093 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:57,094 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_flows_kill _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6593468>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-546 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flows_kill>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6593468>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:57,322 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:57,324 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:57,325 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:57,328 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:57,328 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:57,329 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_room_flow _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9770bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-547 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_room_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9770bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:57,521 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:57,523 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:57,524 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:57,526 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:57,527 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:57,527 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_return ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf65eef90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-548 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_return>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf65eef90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:57,744 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:57,746 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:57,747 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:57,751 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:57,751 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:57,751 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_i18n_simple_name ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fd3420>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-549 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_simple_name>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fd3420>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:57,921 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:57,923 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:57,924 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:57,926 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:57,927 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:57,927 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_prefix ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fd37e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-550 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fd37e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:58,100 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:58,102 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:58,102 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:58,105 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:58,105 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:58,106 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_suffix ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf6602de0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-551 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_suffix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf6602de0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:58,280 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:58,283 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:58,283 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:58,286 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:58,286 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:58,286 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_linked_plugin_here ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65723c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-552 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_linked_plugin_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65723c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:58,456 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:58,459 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:58,459 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:58,462 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:58,462 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:58,463 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_botmatch_correct ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65fb678>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-553 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botmatch_correct>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe65fb678>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:58,632 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:58,634 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:58,634 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:58,637 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:58,638 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:58,638 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_botmatch ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6feffc0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-554 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botmatch>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6feffc0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:58,884 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:58,887 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:58,887 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:58,890 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:58,890 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:58,890 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_foreign_mention ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fefff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-555 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_foreign_mention>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fefff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,085 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,089 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,089 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,092 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,092 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,092 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_testbot_mention ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd5bfd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-556 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_testbot_mention>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd5bfd8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,259 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,262 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,262 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,266 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,266 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,266 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_multiple_mentions ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd6f510>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-557 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_multiple_mentions>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedd6f510>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,434 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,436 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,436 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,439 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,439 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,439 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_plugin_methods _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97af228>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-558 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_methods>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe97af228>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,613 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,615 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,615 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,618 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,618 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,619 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________ ERROR at setup of test_create_join_leave_destroy_lifecycle __________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fefe70>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-559 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_create_join_leave_destroy_lifecycle>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fefe70>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,795 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,797 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,797 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,800 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,800 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,801 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_occupants _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe655ac48>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-560 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_occupants>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe655ac48>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 02:59:59,968 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 02:59:59,970 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 02:59:59,970 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 02:59:59,974 DEBUG    errbot.core               ErrBot init.
2025-01-28 02:59:59,974 DEBUG    errbot.backends.base      Backend init.
2025-01-28 02:59:59,975 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________________ ERROR at setup of test_topic _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-561 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_topic>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1bb8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:00,142 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:00,144 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:00,144 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:00,147 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:00,148 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:00,148 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
___________________ ERROR at setup of test_plugin_callbacks ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1690>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-562 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_callbacks>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1690>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:00,319 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:00,321 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:00,321 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:00,324 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:00,325 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:00,325 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_botcommands ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1f30>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-563 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botcommands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6fb1f30>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:00,498 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:00,500 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:00,500 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:00,503 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:00,503 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:00,504 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________________ ERROR at setup of test_first _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8886ba0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-564 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_first>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8886ba0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:00,672 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:00,674 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:00,675 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:00,678 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:00,678 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:00,679 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_second _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad6e9d8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-565 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_second>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad6e9d8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:00,846 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:00,849 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:00,849 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:00,852 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:00,852 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:00,852 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_failed_config _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad6ea38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-566 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_failed_config>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad6ea38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:01,027 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:01,029 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:01,029 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:01,033 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:01,033 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:01,033 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_failed_config _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad80198>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-567 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_failed_config>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad80198>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:01,215 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:01,217 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:01,217 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:01,220 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:01,221 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:01,221 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_delayed_hello _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad80030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-568 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_delayed_hello>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad80030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:01,434 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:01,437 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:01,437 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:01,514 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:01,515 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:01,515 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_delayed_hello_loop ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff932d20>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-569 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_delayed_hello_loop>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff932d20>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:01,684 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:01,686 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:01,686 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:01,689 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:01,689 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:01,690 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_nosyntax ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad58e40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-620 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_nosyntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad58e40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:01,919 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:01,921 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:01,921 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:01,924 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:01,925 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:01,925 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________________ ERROR at setup of test_syntax _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf6602ab0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-621 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf6602ab0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,094 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,096 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,096 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,100 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,100 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,100 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_re_syntax _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8839d68>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-622 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_re_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8839d68>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,270 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,272 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,272 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,275 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,275 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,276 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_arg_syntax _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff974810>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-623 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_arg_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff974810>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,448 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,450 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,450 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,453 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,453 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,454 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_1 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad52528>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-624 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_1>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad52528>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,621 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,623 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,624 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,627 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,627 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,627 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_2 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8804180>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-625 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_2>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8804180>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,797 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,799 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,799 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,802 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,802 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,803 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_3 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad52b58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-626 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_3>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xad52b58>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:02,971 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:02,973 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:02,973 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:02,977 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:02,977 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:02,977 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_4 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff9cb9c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-627 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_4>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xff9cb9c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:03,153 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:03,155 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:03,155 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:03,159 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:03,159 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:03,159 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_5 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffc060c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-628 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_5>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffc060c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:03,328 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:03,330 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:03,330 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:03,334 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:03,334 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:03,335 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________ ERROR at setup of test_not_configured_url_returns_404 _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6b88>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-629 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_not_configured_url_returns_404>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6b88>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:03,533 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:03,535 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:03,536 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:03,539 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:03,539 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:03,540 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
__________________ ERROR at setup of test_webserver_plugin_ok __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffc01888>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-630 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webserver_plugin_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffc01888>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:03,712 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:03,715 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:03,715 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:03,718 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:03,718 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:03,719 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_________________ ERROR at setup of test_trailing_no_slash_ok __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6b70>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-631 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_trailing_no_slash_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6b70>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:03,892 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:03,894 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:03,895 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:03,898 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:03,898 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:03,899 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
________________ ERROR at setup of test_trailing_slash_also_ok _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffabe0a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-632 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_trailing_slash_also_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffabe0a8>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:04,183 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:04,185 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:04,185 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:04,188 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:04,189 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:04,189 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_____________ ERROR at setup of test_json_is_automatically_decoded _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffabe078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-633 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_json_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffabe078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:04,364 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:04,366 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:04,366 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:04,370 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:04,370 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:04,371 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
______ ERROR at setup of test_json_on_custom_url_is_automatically_decoded ______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8804798>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-634 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_json_on_custom_url_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x8804798>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:04,547 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:04,550 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:04,550 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:04,553 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:04,553 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:04,554 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_ ERROR at setup of test_post_form_on_webhook_without_form_param_is_automatically_decoded _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x87f2a08>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-635 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_post_form_on_webhook_without_form_param_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x87f2a08>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:04,740 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:04,743 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:04,743 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:04,747 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:04,747 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:04,747 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_ ERROR at setup of test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6ff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-636 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xffbe6ff0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:04,959 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:04,962 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:04,962 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:04,966 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:04,967 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:04,967 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_ ERROR at setup of test_webhooks_with_form_parameter_decode_json_automatically _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6f98078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-637 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_form_parameter_decode_json_automatically>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6f98078>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:05,160 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:05,162 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:05,162 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:05,166 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:05,166 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:05,166 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_ ERROR at setup of test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174f00>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-638 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174f00>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:05,340 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:05,342 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:05,342 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:05,345 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:05,345 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:05,346 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______________ ERROR at setup of test_webhooks_with_raw_request _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174e40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-639 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_raw_request>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea174e40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:05,521 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:05,523 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:05,523 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:05,526 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:05,526 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:05,526 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______ ERROR at setup of test_webhooks_with_naked_decorator_raw_request _______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6f98288>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-640 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_naked_decorator_raw_request>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6f98288>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:05,702 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:05,704 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:05,704 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:05,707 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:05,707 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:05,708 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
_______ ERROR at setup of test_generate_certificate_creates_usable_cert ________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60498>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-641 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_generate_certificate_creates_usable_cert>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8d60498>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:05,878 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:05,880 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:05,880 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:05,884 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:05,884 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:05,884 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________ ERROR at setup of test_custom_headers_and_status_codes ____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1c8a38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-642 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_custom_headers_and_status_codes>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1c8a38>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:06,054 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:06,056 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:06,056 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:06,059 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:06,059 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:06,060 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
____________________ ERROR at setup of test_lambda_webhook _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1c8390>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.12/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.12/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.12/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.12/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.12/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-643 (worker), initial daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_lambda_webhook>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea1c8390>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:06,231 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:06,233 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:06,233 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:06,236 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:06,236 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:06,237 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
           ^^^^^^^^^^^^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
  File "/usr/lib/python3.12/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
  File "/usr/lib/python3.12/threading.py", line 994, in start
    _start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
=================================== FAILURES ===================================
________________________________ test_streaming ________________________________

    def test_streaming():
        canary = b"this is my test" * 1000
        source = Stream(TestPerson("gbin@gootz.net"), BytesIO(canary))
        clients = [StreamingClient() for _ in range(50)]
>       Tee(source, clients).run()

tests/streaming_test.py:17: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/streaming.py:81: in run
    thread.start()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Thread(Thread-570 (streamer), initial)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
>           _start_new_thread(self._bootstrap, ())
E           RuntimeError: can't start new thread

/usr/lib/python3.12/threading.py:994: RuntimeError
=============================== warnings summary ===============================
../../../errbot/utils.py:13
  /build/reproducible-path/errbot-6.2.0+ds/errbot/utils.py:13: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
    import pkg_resources

.pybuild/cpython3_3.12_errbot/build/tests/cascade_dependencies_test.py::test_dependency_commands
  /usr/lib/python3/dist-packages/webob/compat.py:5: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
    from cgi import parse_header

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/streaming_test.py::test_streaming - RuntimeError: can't start ne...
ERROR tests/commands_test.py::test_echo - SystemExit: -1
ERROR tests/commands_test.py::test_status_gc - SystemExit: -1
ERROR tests/commands_test.py::test_config_cycle - SystemExit: -1
ERROR tests/commands_test.py::test_apropos - SystemExit: -1
ERROR tests/commands_test.py::test_logtail - SystemExit: -1
ERROR tests/commands_test.py::test_history - SystemExit: -1
ERROR tests/commands_test.py::test_encoding_preservation - SystemExit: -1
ERROR tests/commands_test.py::test_webserver_webhook_test - SystemExit: -1
ERROR tests/commands_test.py::test_activate_reload_and_deactivate - SystemExi...
ERROR tests/commands_test.py::test_unblacklist_and_blacklist - SystemExit: -1
ERROR tests/commands_test.py::test_optional_prefix - SystemExit: -1
ERROR tests/commands_test.py::test_optional_prefix_re_cmd - SystemExit: -1
ERROR tests/commands_test.py::test_simple_match - SystemExit: -1
ERROR tests/commands_test.py::test_no_suggest_on_re_commands - SystemExit: -1
ERROR tests/commands_test.py::test_callback_no_command - SystemExit: -1
ERROR tests/commands_test.py::test_subcommands - SystemExit: -1
ERROR tests/commands_test.py::test_command_not_found_with_space_in_bot_prefix
ERROR tests/commands_test.py::test_mock_injection - SystemExit: -1
ERROR tests/commands_test.py::test_multiline_command - SystemExit: -1
ERROR tests/commands_test.py::test_plugin_info_command - SystemExit: -1
ERROR tests/core_plugins_test.py::test_help_is_still_here - SystemExit: -1
ERROR tests/core_plugins_test.py::test_echo_still_here - SystemExit: -1
ERROR tests/core_plugins_test.py::test_bot_prefix_replaced - SystemExit: -1
ERROR tests/core_test.py::test_admins_to_notify - SystemExit: -1
ERROR tests/core_test.py::test_admins_not_notified - SystemExit: -1
ERROR tests/dependencies_test.py::test_if_all_loaded_by_default - SystemExit: -1
ERROR tests/dependencies_test.py::test_single_dependency - SystemExit: -1
ERROR tests/dependencies_test.py::test_double_dependency - SystemExit: -1
ERROR tests/dependencies_test.py::test_dependency_retrieval - SystemExit: -1
ERROR tests/dependencies_test.py::test_direct_circular_dependency - SystemExi...
ERROR tests/dependencies_test.py::test_indirect_circular_dependency - SystemE...
ERROR tests/dependencies_test.py::test_chained_dependency - SystemExit: -1
ERROR tests/dynaplug_test.py::test_simple - SystemExit: -1
ERROR tests/dynaplug_test.py::test_arg - SystemExit: -1
ERROR tests/dynaplug_test.py::test_re - SystemExit: -1
ERROR tests/dynaplug_test.py::test_saw - SystemExit: -1
ERROR tests/dynaplug_test.py::test_clashing - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_list_flows - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_no_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_no_duplicate_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_secondary_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_manual_flow - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_manual_flow_with_or_without_hinting - Syst...
ERROR tests/flow_e2e_test.py::test_no_flyby_trigger_flow - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flow_only - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flow_only_help - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flows_stop - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flows_kill - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_room_flow - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_return - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_simple_name - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_prefix - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_suffix - SystemExit: -1
ERROR tests/link_test.py::test_linked_plugin_here - SystemExit: -1
ERROR tests/matchall_test.py::test_botmatch_correct - SystemExit: -1
ERROR tests/matchall_test.py::test_botmatch - SystemExit: -1
ERROR tests/mention_test.py::test_foreign_mention - SystemExit: -1
ERROR tests/mention_test.py::test_testbot_mention - SystemExit: -1
ERROR tests/mention_test.py::test_multiple_mentions - SystemExit: -1
ERROR tests/muc_test.py::test_plugin_methods - SystemExit: -1
ERROR tests/muc_test.py::test_create_join_leave_destroy_lifecycle - SystemExi...
ERROR tests/muc_test.py::test_occupants - SystemExit: -1
ERROR tests/muc_test.py::test_topic - SystemExit: -1
ERROR tests/muc_test.py::test_plugin_callbacks - SystemExit: -1
ERROR tests/muc_test.py::test_botcommands - SystemExit: -1
ERROR tests/multi_plugin_test.py::test_first - SystemExit: -1
ERROR tests/multi_plugin_test.py::test_second - SystemExit: -1
ERROR tests/plugin_config_fail_test.py::test_failed_config - SystemExit: -1
ERROR tests/plugin_config_test.py::test_failed_config - SystemExit: -1
ERROR tests/poller_test.py::test_delayed_hello - SystemExit: -1
ERROR tests/poller_test.py::test_delayed_hello_loop - SystemExit: -1
ERROR tests/syntax_test.py::test_nosyntax - SystemExit: -1
ERROR tests/syntax_test.py::test_syntax - SystemExit: -1
ERROR tests/syntax_test.py::test_re_syntax - SystemExit: -1
ERROR tests/syntax_test.py::test_arg_syntax - SystemExit: -1
ERROR tests/templates_test.py::test_templates_1 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_2 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_3 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_4 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_5 - SystemExit: -1
ERROR tests/webhooks_test.py::test_not_configured_url_returns_404 - SystemExi...
ERROR tests/webhooks_test.py::test_webserver_plugin_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_trailing_no_slash_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_trailing_slash_also_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_json_is_automatically_decoded - SystemExit...
ERROR tests/webhooks_test.py::test_json_on_custom_url_is_automatically_decoded
ERROR tests/webhooks_test.py::test_post_form_on_webhook_without_form_param_is_automatically_decoded
ERROR tests/webhooks_test.py::test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded
ERROR tests/webhooks_test.py::test_webhooks_with_form_parameter_decode_json_automatically
ERROR tests/webhooks_test.py::test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically
ERROR tests/webhooks_test.py::test_webhooks_with_raw_request - SystemExit: -1
ERROR tests/webhooks_test.py::test_webhooks_with_naked_decorator_raw_request
ERROR tests/webhooks_test.py::test_generate_certificate_creates_usable_cert
ERROR tests/webhooks_test.py::test_custom_headers_and_status_codes - SystemEx...
ERROR tests/webhooks_test.py::test_lambda_webhook - SystemExit: -1
===== 1 failed, 110 passed, 8 deselected, 2 warnings, 96 errors in 23.57s ======
E: pybuild pybuild:389: test: plugin distutils failed with: exit code=1: cd /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.12_errbot/build; python3.12 -m pytest -k "not test_broken_plugin and not test_backup and not test_plugin_cycle and not test_entrypoint_paths and not test_check_dependencies_requirements_file_all_installed"
I: pybuild pybuild:308: rm -f /build/reproducible-path/errbot-6.2.0+ds/tests/backend_tests/slack_test.py
I: pybuild base:311: cd /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build; python3.13 -m pytest -k "not test_broken_plugin and not test_backup and not test_plugin_cycle and not test_entrypoint_paths and not test_check_dependencies_requirements_file_all_installed"
============================= test session starts ==============================
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
rootdir: /build/reproducible-path/errbot-6.2.0+ds
plugins: typeguard-4.4.1
collected 215 items / 8 deselected / 207 selected

tests/backend_manager_test.py ...                                        [  1%]
tests/backend_tests/text_test.py .                                       [  1%]
tests/base_backend_test.py .................................             [ 17%]
tests/cascade_dependencies_test.py .                                     [ 18%]
tests/circular_dependencies_test.py .                                    [ 18%]
tests/commands_test.py ........EEEEEEEEEEEEEEEEEEEE                      [ 32%]
tests/core_plugins_test.py EEE                                           [ 33%]
tests/core_test.py EE                                                    [ 34%]
tests/dependencies_test.py EEEEEEE                                       [ 38%]
tests/dynaplug_test.py EEEEE                                             [ 40%]
tests/flow_e2e_test.py EEEEEEEEEEEEE                                     [ 46%]
tests/flow_test.py ...                                                   [ 48%]
tests/i18n_test.py EEEE                                                  [ 50%]
tests/link_test.py E                                                     [ 50%]
tests/matchall_test.py EE                                                [ 51%]
tests/md_rendering_test.py ....                                          [ 53%]
tests/mention_test.py EEE                                                [ 55%]
tests/muc_test.py EEEEEE                                                 [ 57%]
tests/multi_plugin_test.py EE                                            [ 58%]
tests/persistence_test.py ..                                             [ 59%]
tests/plugin_config_fail_test.py E                                       [ 60%]
tests/plugin_config_test.py .......E                                     [ 64%]
tests/plugin_info_test.py ........                                       [ 68%]
tests/plugin_management_test.py .......                                  [ 71%]
tests/poller_test.py EE                                                  [ 72%]
tests/repo_manager_test.py .......                                       [ 75%]
tests/simple_identifiers_test.py .....                                   [ 78%]
tests/streaming_test.py F                                                [ 78%]
tests/syntax_test.py EEEE                                                [ 80%]
tests/templates_test.py EEEEE                                            [ 83%]
tests/utils_test.py ....................                                 [ 92%]
tests/webhooks_test.py EEEEEEEEEEEEEEE                                   [100%]

==================================== ERRORS ====================================
_________________________ ERROR at setup of test_echo __________________________

self = <multiprocessing.pool.ThreadPool state=INIT pool_size=1>, processes = 10
initializer = None, initargs = (), maxtasksperchild = None, context = None

    def __init__(self, processes=None, initializer=None, initargs=(),
                 maxtasksperchild=None, context=None):
        # Attributes initialized early to make sure that they exist in
        # __del__() if __init__() raises an exception
        self._pool = []
        self._state = INIT
    
        self._ctx = context or get_context()
        self._setup_queues()
        self._taskqueue = queue.SimpleQueue()
        # The _change_notifier queue exist to wake up self._handle_workers()
        # when the cache (self._cache) is empty or when there is a change in
        # the _state variable of the thread that runs _handle_workers.
        self._change_notifier = self._ctx.SimpleQueue()
        self._cache = _PoolCache(notifier=self._change_notifier)
        self._maxtasksperchild = maxtasksperchild
        self._initializer = initializer
        self._initargs = initargs
    
        if processes is None:
            processes = os.process_cpu_count() or 1
        if processes < 1:
            raise ValueError("Number of processes must be at least 1")
        if maxtasksperchild is not None:
            if not isinstance(maxtasksperchild, int) or maxtasksperchild <= 0:
                raise ValueError("maxtasksperchild must be a positive int or None")
    
        if initializer is not None and not callable(initializer):
            raise TypeError('initializer must be a callable')
    
        self._processes = processes
        try:
>           self._repopulate_pool()

/usr/lib/python3.13/multiprocessing/pool.py:215: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-497 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed198c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <multiprocessing.pool.ThreadPool state=INIT pool_size=1>, processes = 10
initializer = None, initargs = (), maxtasksperchild = None, context = None

    def __init__(self, processes=None, initializer=None, initargs=(),
                 maxtasksperchild=None, context=None):
        # Attributes initialized early to make sure that they exist in
        # __del__() if __init__() raises an exception
        self._pool = []
        self._state = INIT
    
        self._ctx = context or get_context()
        self._setup_queues()
        self._taskqueue = queue.SimpleQueue()
        # The _change_notifier queue exist to wake up self._handle_workers()
        # when the cache (self._cache) is empty or when there is a change in
        # the _state variable of the thread that runs _handle_workers.
        self._change_notifier = self._ctx.SimpleQueue()
        self._cache = _PoolCache(notifier=self._change_notifier)
        self._maxtasksperchild = maxtasksperchild
        self._initializer = initializer
        self._initargs = initargs
    
        if processes is None:
            processes = os.process_cpu_count() or 1
        if processes < 1:
            raise ValueError("Number of processes must be at least 1")
        if maxtasksperchild is not None:
            if not isinstance(maxtasksperchild, int) or maxtasksperchild <= 0:
                raise ValueError("maxtasksperchild must be a positive int or None")
    
        if initializer is not None and not callable(initializer):
            raise TypeError('initializer must be a callable')
    
        self._processes = processes
        try:
            self._repopulate_pool()
        except Exception:
            for p in self._pool:
                if p.exitcode is None:
>                   p.terminate()
E                   AttributeError: 'DummyProcess' object has no attribute 'terminate'

/usr/lib/python3.13/multiprocessing/pool.py:219: AttributeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_echo>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xed198c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 219, in __init__
    p.terminate()
    ^^^^^^^^^^^
AttributeError: 'DummyProcess' object has no attribute 'terminate'
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:11,329 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:11,331 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:11,331 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:11,333 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:11,333 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:11,334 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 219, in __init__
    p.terminate()
    ^^^^^^^^^^^
AttributeError: 'DummyProcess' object has no attribute 'terminate'
_______________________ ERROR at setup of test_status_gc _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68f50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-498 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_status_gc>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68f50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:11,515 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:11,517 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:11,517 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:11,519 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:11,519 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:11,553 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_config_cycle ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-499 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_config_cycle>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:11,700 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:11,703 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:11,703 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:11,704 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:11,704 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:11,705 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_apropos ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb687c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-500 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_apropos>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb687c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:11,847 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:11,850 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:11,850 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:11,851 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:11,851 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:11,852 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_logtail ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde5b30>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-501 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_logtail>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde5b30>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:11,995 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:11,997 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:11,997 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:11,998 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:11,998 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:11,999 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_history ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-502 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_history>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,140 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,142 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,142 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,144 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,144 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,144 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________ ERROR at setup of test_encoding_preservation _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-503 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_encoding_preservation>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,284 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,286 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,286 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,288 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,288 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,288 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________ ERROR at setup of test_webserver_webhook_test _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb687c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-504 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webserver_webhook_test>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb687c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,432 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,434 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,434 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,436 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,436 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,436 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________ ERROR at setup of test_activate_reload_and_deactivate _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-505 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_activate_reload_and_deactivate>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,577 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,579 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,579 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,581 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,581 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,581 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________ ERROR at setup of test_unblacklist_and_blacklist _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-506 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_unblacklist_and_blacklist>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,727 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,729 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,729 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,731 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,731 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,732 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_optional_prefix ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-507 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_optional_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:12,873 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:12,875 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:12,875 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:12,877 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:12,877 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:12,877 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________ ERROR at setup of test_optional_prefix_re_cmd _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-508 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_optional_prefix_re_cmd>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,019 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,021 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,021 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,023 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,023 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,023 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_simple_match ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-509 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_simple_match>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,167 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,169 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,170 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,171 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,172 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,172 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________ ERROR at setup of test_no_suggest_on_re_commands _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abc90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-510 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_suggest_on_re_commands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abc90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,313 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,315 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,315 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,317 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,317 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,318 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_callback_no_command __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-511 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_callback_no_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,463 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,465 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,465 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,467 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,467 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,467 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_subcommands ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abd40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-512 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_subcommands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abd40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,609 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,611 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,611 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,613 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,613 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,614 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______ ERROR at setup of test_command_not_found_with_space_in_bot_prefix _______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea969c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-513 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_command_not_found_with_space_in_bot_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea969c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,755 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,757 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,757 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,759 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,759 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,759 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_mock_injection _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abd40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-514 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_mock_injection>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abd40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:13,902 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:13,904 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:13,905 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:13,906 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:13,907 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:13,907 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_multiline_command ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9693a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-515 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_multiline_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9693a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,048 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,050 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,050 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,052 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,052 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,052 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_plugin_info_command __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab7c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-516 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_info_command>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab7c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,201 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,203 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,204 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,206 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,206 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,206 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_help_is_still_here ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-517 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_help_is_still_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,350 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,352 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,353 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,354 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,355 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,355 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_echo_still_here ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-518 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_echo_still_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,504 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,506 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,506 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,508 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,508 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,508 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_bot_prefix_replaced __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b565b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-519 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_bot_prefix_replaced>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b565b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'CORE_PLUGINS': ('Help', 'Utils', 'CommandNotFoundFilter'), 'BOT_ALT_PREFIXES': ('!',), 'BOT_PREFIX': '$'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,734 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,736 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,737 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,739 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,739 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,739 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_admins_to_notify ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea969c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-520 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_admins_to_notify>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea969c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'BOT_ADMINS_NOTIFICATIONS': 'zoni@localdomain'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:14,881 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:14,883 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:14,883 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:14,885 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:14,886 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:14,886 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_admins_not_notified __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abc90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-521 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_admins_not_notified>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9abc90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
DEBUG    errbot.backends.test      Merging {'BOT_ADMINS_NOTIFICATIONS': 'zoni@localdomain'} to the bot config.
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,031 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,033 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,033 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,035 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,035 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,036 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________ ERROR at setup of test_if_all_loaded_by_default ________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b565b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-522 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_if_all_loaded_by_default>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b565b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,178 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,180 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,180 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,183 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,183 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,183 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_single_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde53a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-523 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_single_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde53a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,331 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,333 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,333 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,335 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,335 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,336 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_double_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-524 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_double_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,477 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,479 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,479 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,481 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,482 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,482 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________ ERROR at setup of test_dependency_retrieval __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-525 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_dependency_retrieval>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,623 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,625 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,626 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,628 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,628 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,628 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________ ERROR at setup of test_direct_circular_dependency _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-526 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_direct_circular_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,773 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,775 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,775 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,777 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,777 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,778 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________ ERROR at setup of test_indirect_circular_dependency ______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde53a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-527 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_indirect_circular_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde53a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:15,922 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:15,924 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:15,924 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:15,926 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:15,926 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:15,927 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_chained_dependency ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-528 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_chained_dependency>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,073 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,076 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,076 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,078 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,078 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,078 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_simple _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-529 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_simple>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,221 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,223 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,223 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,226 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,226 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,226 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_arg __________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-530 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_arg>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,367 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,369 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,370 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,372 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,372 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,372 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_re ___________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-531 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_re>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,516 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,518 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,518 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,521 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,521 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,521 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________________ ERROR at setup of test_saw __________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee5703a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-532 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_saw>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee5703a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,665 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,667 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,667 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,669 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,669 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,670 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_clashing ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-533 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_clashing>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,816 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,818 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,818 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,821 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,821 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,821 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_list_flows _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-534 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_list_flows>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:16,963 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:16,965 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:16,965 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:16,968 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:16,968 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:16,968 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_no_autotrigger _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-535 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,115 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,117 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,117 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,120 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,120 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,120 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_autotrigger ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-536 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,263 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,265 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,265 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,268 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,268 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,268 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________ ERROR at setup of test_no_duplicate_autotrigger ________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-537 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_duplicate_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,452 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,454 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,454 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,458 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,458 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,459 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________ ERROR at setup of test_secondary_autotrigger _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-538 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_secondary_autotrigger>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,615 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,617 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,618 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,620 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,620 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,621 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_manual_flow ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-539 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_manual_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8b567c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,765 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,767 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,767 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,770 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,770 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,770 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________ ERROR at setup of test_manual_flow_with_or_without_hinting __________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-540 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_manual_flow_with_or_without_hinting>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe8bdc500>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:17,923 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:17,925 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:17,925 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:17,928 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:17,928 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:17,928 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________ ERROR at setup of test_no_flyby_trigger_flow _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf21cc3a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-541 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_no_flyby_trigger_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf21cc3a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,077 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,080 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,080 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,083 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,083 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,083 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_flow_only _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe81d8d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-542 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flow_only>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe81d8d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,248 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,250 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,250 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,252 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,252 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,253 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_flow_only_help _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf21cc3a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-543 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flow_only_help>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf21cc3a0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,401 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,404 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,404 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,407 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,407 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,408 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_flows_stop _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-544 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flows_stop>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,553 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,555 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,556 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,558 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,558 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,559 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_flows_kill _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7190>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-545 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_flows_kill>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7190>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,810 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,813 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,813 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,815 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,815 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,816 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_room_flow _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-546 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_room_flow>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee59ddf0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:18,965 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:18,968 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:18,968 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:18,970 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:18,971 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:18,971 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_return ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-547 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_return>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe9fa7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,118 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,120 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,120 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,123 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,123 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,123 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_i18n_simple_name ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-548 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_simple_name>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,271 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,273 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,273 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,275 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,275 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,276 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_prefix ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-549 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_prefix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab450>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,419 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,421 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,421 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,424 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,424 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,424 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_i18n_suffix ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb810e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-550 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_i18n_suffix>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb810e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,573 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,576 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,576 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,578 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,578 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,579 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_linked_plugin_here ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-551 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_linked_plugin_here>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,732 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,734 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,734 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,737 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,737 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,737 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_botmatch_correct ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-552 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botmatch_correct>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:19,885 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:19,887 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:19,887 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:19,890 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:19,890 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:19,891 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_botmatch ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-553 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botmatch>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,032 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,034 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,034 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,036 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,037 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,037 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_foreign_mention ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb810e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-554 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_foreign_mention>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb810e0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,186 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,188 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,188 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,192 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,192 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,192 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_testbot_mention ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-555 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_testbot_mention>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,338 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,340 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,341 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,343 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,343 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,344 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_multiple_mentions ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-556 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_multiple_mentions>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,485 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,487 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,488 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,490 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,490 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,491 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_plugin_methods _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-557 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_methods>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,636 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,638 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,638 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,641 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,641 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,641 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________ ERROR at setup of test_create_join_leave_destroy_lifecycle __________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-558 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_create_join_leave_destroy_lifecycle>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,784 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,786 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,786 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,789 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,789 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,790 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_occupants _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-559 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_occupants>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:20,943 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:20,946 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:20,946 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:20,949 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:20,949 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:20,950 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________________ ERROR at setup of test_topic _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-560 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_topic>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,105 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,107 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,107 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,110 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,110 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,111 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
___________________ ERROR at setup of test_plugin_callbacks ____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639fa80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-561 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_plugin_callbacks>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639fa80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,257 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,259 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,259 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,262 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,262 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,263 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_botcommands ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-562 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_botcommands>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,422 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,424 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,425 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,427 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,427 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,428 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________________ ERROR at setup of test_first _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-563 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_first>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3aef50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,573 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,575 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,575 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,578 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,578 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,578 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_second _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-564 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_second>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,728 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,730 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,730 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,733 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,733 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,734 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_failed_config _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f240>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-565 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_failed_config>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f240>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:21,883 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:21,885 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:21,885 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:21,888 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:21,888 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:21,888 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_failed_config _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-566 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_failed_config>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9cf0660>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:22,052 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:22,054 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:22,054 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:22,057 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:22,057 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:22,058 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________________ ERROR at setup of test_delayed_hello _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9a61870>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-567 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_delayed_hello>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9a61870>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:22,244 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:22,246 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:22,246 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:22,249 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:22,249 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:22,250 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_delayed_hello_loop ___________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6d8bf50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-568 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_delayed_hello_loop>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6d8bf50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:22,403 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:22,406 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:22,406 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:22,409 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:22,409 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:22,410 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_nosyntax ________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6d8b7c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-619 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_nosyntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe6d8b7c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:22,657 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:22,659 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:22,659 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:22,662 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:22,663 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:22,663 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________________ ERROR at setup of test_syntax _________________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639ff50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-620 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639ff50>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:22,933 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:22,935 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:22,936 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:22,938 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:22,938 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:22,939 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________________ ERROR at setup of test_re_syntax _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-621 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_re_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xf3fd7ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,086 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,088 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,088 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,091 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,091 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,091 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_arg_syntax _______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-622 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_arg_syntax>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,247 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,249 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,249 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,252 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,252 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,253 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_1 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-623 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_1>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,402 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,404 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,404 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,407 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,407 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,408 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_2 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-624 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_2>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xea9ab030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,560 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,562 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,562 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,565 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,565 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,566 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_3 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-625 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_3>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,714 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,716 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,717 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,719 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,720 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,720 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_4 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-626 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_4>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe639f710>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:23,867 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:23,869 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:23,869 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:23,872 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:23,872 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:23,873 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______________________ ERROR at setup of test_templates_5 ______________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae5b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-627 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_templates_5>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae5b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,026 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,028 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,028 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,031 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,032 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,032 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________ ERROR at setup of test_not_configured_url_returns_404 _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-628 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_not_configured_url_returns_404>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xe95c4ea0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,208 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,210 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,210 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,213 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,214 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,214 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
__________________ ERROR at setup of test_webserver_plugin_ok __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-629 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webserver_plugin_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae030>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,368 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,370 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,370 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,373 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,373 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,374 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_________________ ERROR at setup of test_trailing_no_slash_ok __________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb817c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-630 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_trailing_no_slash_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb817c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,523 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,525 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,525 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,528 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,528 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,529 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
________________ ERROR at setup of test_trailing_slash_also_ok _________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae5b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-631 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_trailing_slash_also_ok>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xeb3ae5b0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,681 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,683 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,683 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,686 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,687 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,687 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_____________ ERROR at setup of test_json_is_automatically_decoded _____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb817c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-632 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_json_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb817c0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,837 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,839 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,840 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,843 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,843 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,843 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
______ ERROR at setup of test_json_on_custom_url_is_automatically_decoded ______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde5c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-633 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_json_on_custom_url_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xebde5c90>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:24,989 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:24,991 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:24,991 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:24,994 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:24,994 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:24,995 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_ ERROR at setup of test_post_form_on_webhook_without_form_param_is_automatically_decoded _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-634 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_post_form_on_webhook_without_form_param_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,142 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,144 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,144 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,147 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,147 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,148 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_ ERROR at setup of test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb81870>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-635 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb81870>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,294 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,296 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,296 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,299 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,300 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,300 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_ ERROR at setup of test_webhooks_with_form_parameter_decode_json_automatically _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68be0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-636 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_form_parameter_decode_json_automatically>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68be0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,444 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,447 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,447 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,450 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,450 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,450 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_ ERROR at setup of test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically _

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-637 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xec7f1a80>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,594 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,596 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,596 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,599 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,600 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,600 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______________ ERROR at setup of test_webhooks_with_raw_request _______________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee570d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-638 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_raw_request>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xee570d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,745 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,747 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,747 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,750 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,751 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,751 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______ ERROR at setup of test_webhooks_with_naked_decorator_raw_request _______

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68be0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-639 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_webhooks_with_naked_decorator_raw_request>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68be0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:25,895 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:25,897 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:25,897 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:25,900 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:25,900 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:25,901 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
_______ ERROR at setup of test_generate_certificate_creates_usable_cert ________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9c4abe0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-640 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_generate_certificate_creates_usable_cert>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9c4abe0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:26,045 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:26,047 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:26,047 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:26,051 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:26,051 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:26,051 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________ ERROR at setup of test_custom_headers_and_status_codes ____________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-641 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_custom_headers_and_status_codes>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0xedb68d40>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:26,197 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:26,199 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:26,199 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:26,202 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:26,202 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:26,203 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
____________________ ERROR at setup of test_lambda_webhook _____________________

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9c4abe0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
>           bot = backendpm.load_plugin()

../../../errbot/bootstrap.py:186: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backend_plugin_manager.py:72: in load_plugin
    return clazz(self._config)
../../../errbot/backends/test.py:273: in __init__
    super().__init__(config)
../../../errbot/core.py:53: in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
/usr/lib/python3.13/multiprocessing/pool.py:930: in __init__
    Pool.__init__(self, processes, initializer, initargs)
/usr/lib/python3.13/multiprocessing/pool.py:215: in __init__
    self._repopulate_pool()
/usr/lib/python3.13/multiprocessing/pool.py:306: in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
/usr/lib/python3.13/multiprocessing/pool.py:329: in _repopulate_pool_static
    w.start()
/usr/lib/python3.13/multiprocessing/dummy/__init__.py:51: in start
    threading.Thread.start(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <DummyProcess(Thread-642 (worker), stopped daemon)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError

During handling of the above exception, another exception occurred:

request = <SubRequest 'testbot' for <Function test_lambda_webhook>>

    @pytest.fixture
    def testbot(request) -> TestBot:
        """
        Pytest fixture to write tests against a fully functioning bot.
    
        For example, if you wanted to test the builtin `!about` command,
        you could write a test file with the following::
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        It's possible to provide additional configuration to this fixture,
        by setting variables at module level or as class attributes (the
        latter taking precedence over the former). For example::
    
            extra_plugin_dir = '/foo/bar'
    
            def test_about(testbot):
                testbot.push_message('!about')
                assert "Err version" in testbot.pop_message()
    
        ..or::
    
            extra_plugin_dir = '/foo/bar'
    
            class Tests:
                # Wins over `extra_plugin_dir = '/foo/bar'` above
                extra_plugin_dir = '/foo/baz'
    
                def test_about(self, testbot):
                    testbot.push_message('!about')
                    assert "Err version" in testbot.pop_message()
    
        ..to load additional plugins from the directory `/foo/bar` or
        `/foo/baz` respectively. This works for the following items, which are
        passed to the constructor of :class:`~errbot.backends.test.TestBot`:
    
        * `extra_plugin_dir`
        * `loglevel`
        """
    
        def on_finish() -> TestBot:
            bot.stop()
    
        #  setup the logging to something digestable.
        logger = logging.getLogger("")
        logging.getLogger("MARKDOWN").setLevel(
            logging.ERROR
        )  # this one is way too verbose in debug
        logger.setLevel(logging.DEBUG)
        console_hdlr = logging.StreamHandler(sys.stdout)
        console_hdlr.setFormatter(
            logging.Formatter("%(levelname)-8s %(name)-25s %(message)s")
        )
        logger.handlers = []
        logger.addHandler(console_hdlr)
    
        kwargs = {}
    
        for attr, default in (
            ("extra_plugin_dir", None),
            ("extra_config", None),
            ("loglevel", logging.DEBUG),
        ):
            if hasattr(request, "instance"):
                kwargs[attr] = getattr(request.instance, attr, None)
            if kwargs[attr] is None:
                kwargs[attr] = getattr(request.module, attr, default)
    
        bot = TestBot(**kwargs)
>       bot.start()

../../../errbot/backends/test.py:705: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/backends/test.py:482: in start
    self._bot = setup_bot("Test", self.logger, self.bot_config)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

backend_name = 'Test', logger = <RootLogger root (DEBUG)>
config = <errbot.backends.test.ShallowConfig object at 0x9c4abe0>
restore = None

    def setup_bot(
        backend_name: str,
        logger: logging.Logger,
        config: object,
        restore: Optional[str] = None,
    ) -> ErrBot:
        # from here the environment is supposed to be set (daemon / non daemon,
        # config.py in the python path )
    
        bot_config_defaults(config)
    
        if hasattr(config, "BOT_LOG_FORMATTER"):
            format_logs(formatter=config.BOT_LOG_FORMATTER)
        else:
            format_logs(theme_color=config.TEXT_COLOR_THEME)
    
        if hasattr(config, "BOT_LOG_FILE") and config.BOT_LOG_FILE:
            hdlr = logging.FileHandler(config.BOT_LOG_FILE)
            hdlr.setFormatter(
                logging.Formatter("%(asctime)s %(levelname)-8s %(name)-25s %(message)s")
            )
            logger.addHandler(hdlr)
    
        if hasattr(config, "BOT_LOG_SENTRY") and config.BOT_LOG_SENTRY:
            sentry_integrations = []
    
            try:
                import sentry_sdk
                from sentry_sdk.integrations.logging import LoggingIntegration
    
            except ImportError:
                log.exception(
                    "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                    "needed for Sentry integration. Did you install sentry-sdk? "
                    "(See https://docs.sentry.io/platforms/python for installation instructions)"
                )
                exit(-1)
    
            sentry_logging = LoggingIntegration(
                level=config.SENTRY_LOGLEVEL, event_level=config.SENTRY_EVENTLEVEL
            )
    
            sentry_integrations.append(sentry_logging)
    
            if hasattr(config, "BOT_LOG_SENTRY_FLASK") and config.BOT_LOG_SENTRY_FLASK:
                try:
                    from sentry_sdk.integrations.flask import FlaskIntegration
                except ImportError:
                    log.exception(
                        "You have BOT_LOG_SENTRY enabled, but I couldn't import modules "
                        "needed for Sentry integration. Did you install sentry-sdk[flask]? "
                        "(See https://docs.sentry.io/platforms/python/flask for installation instructions)"
                    )
                    exit(-1)
    
                sentry_integrations.append(FlaskIntegration())
    
            sentry_options = getattr(config, "SENTRY_OPTIONS", {})
            if hasattr(config, "SENTRY_TRANSPORT") and isinstance(
                config.SENTRY_TRANSPORT, tuple
            ):
                warnings.warn(
                    "SENTRY_TRANSPORT is deprecated. Please use SENTRY_OPTIONS instead.",
                    DeprecationWarning,
                )
                try:
                    mod = importlib.import_module(config.SENTRY_TRANSPORT[1])
                    transport = getattr(mod, config.SENTRY_TRANSPORT[0])
                    sentry_options["transport"] = transport
                except ImportError:
                    log.exception(
                        f"Unable to import selected SENTRY_TRANSPORT - {config.SENTRY_TRANSPORT}"
                    )
                    exit(-1)
            # merge options dict with dedicated SENTRY_DSN setting
            sentry_kwargs = {
                **sentry_options,
                **{"dsn": config.SENTRY_DSN, "integrations": sentry_integrations},
            }
            sentry_sdk.init(**sentry_kwargs)
    
        logger.setLevel(config.BOT_LOG_LEVEL)
    
        storage_plugin = get_storage_plugin(config)
    
        # init the botplugin manager
        botplugins_dir = path.join(config.BOT_DATA_DIR, PLUGINS_SUBDIR)
        if not path.exists(botplugins_dir):
            makedirs(botplugins_dir, mode=0o755)
    
        plugin_indexes = getattr(config, "BOT_PLUGIN_INDEXES", (PLUGIN_DEFAULT_INDEX,))
        if isinstance(plugin_indexes, str):
            plugin_indexes = (plugin_indexes,)
    
        # Extra backend is expected to be a list type, convert string to list.
        extra_backend = getattr(config, "BOT_EXTRA_BACKEND_DIR", [])
        if isinstance(extra_backend, str):
            extra_backend = [extra_backend]
    
        backendpm = BackendPluginManager(
            config, "errbot.backends", backend_name, ErrBot, CORE_BACKENDS, extra_backend
        )
    
        log.info(f"Found Backend plugin: {backendpm.plugin_info.name}")
    
        repo_manager = BotRepoManager(storage_plugin, botplugins_dir, plugin_indexes)
    
        try:
            bot = backendpm.load_plugin()
            botpm = BotPluginManager(
                storage_plugin,
                config.BOT_EXTRA_PLUGIN_DIR,
                config.AUTOINSTALL_DEPS,
                getattr(config, "CORE_PLUGINS", None),
                lambda name, clazz: clazz(bot, name),
                getattr(config, "PLUGINS_CALLBACK_ORDER", (None,)),
            )
            bot.attach_storage_plugin(storage_plugin)
            bot.attach_repo_manager(repo_manager)
            bot.attach_plugin_manager(botpm)
            bot.initialize_backend_storage()
    
            # restore the bot from the restore script
            if restore:
                # Prepare the context for the restore script
                if "repos" in bot:
                    log.fatal("You cannot restore onto a non empty bot.")
                    sys.exit(-1)
                log.info(f"**** RESTORING the bot from {restore}")
                restore_bot_from_backup(restore, bot=bot, log=log)
                print("Restore complete. You can restart the bot normally")
                sys.exit(0)
    
            errors = bot.plugin_manager.update_plugin_places(
                repo_manager.get_all_repos_paths()
            )
            if errors:
                startup_errors = "\n".join(errors.values())
                log.error("Some plugins failed to load:\n%s", startup_errors)
                bot._plugin_errors_during_startup = startup_errors
            return bot
        except Exception:
            log.exception("Unable to load or configure the backend.")
>           exit(-1)
E           SystemExit: -1

../../../errbot/bootstrap.py:221: SystemExit
---------------------------- Captured stdout setup -----------------------------
INFO     errbot.bootstrap          Found Storage plugin: Memory.
INFO     errbot.bootstrap          Found Backend plugin: Test
DEBUG    errbot.storage            Opening storage 'repomgr'
DEBUG    errbot.core               ErrBot init.
DEBUG    errbot.backends.base      Backend init.
ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
---------------------------- Captured stderr setup -----------------------------
2025-01-28 03:00:26,349 INFO     errbot.bootstrap          Found Storage plugin: Memory.
2025-01-28 03:00:26,352 INFO     errbot.bootstrap          Found Backend plugin: Test
2025-01-28 03:00:26,352 DEBUG    errbot.storage            Opening storage 'repomgr'
2025-01-28 03:00:26,355 DEBUG    errbot.core               ErrBot init.
2025-01-28 03:00:26,355 DEBUG    errbot.backends.base      Backend init.
2025-01-28 03:00:26,355 ERROR    errbot.bootstrap          Unable to load or configure the backend.
Traceback (most recent call last):
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/bootstrap.py", line 186, in setup_bot
    bot = backendpm.load_plugin()
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backend_plugin_manager.py", line 72, in load_plugin
    return clazz(self._config)
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/backends/test.py", line 273, in __init__
    super().__init__(config)
    ~~~~~~~~~~~~~~~~^^^^^^^^
  File "/build/reproducible-path/errbot-6.2.0+ds/errbot/core.py", line 53, in __init__
    self.thread_pool = ThreadPool(bot_config.BOT_ASYNC_POOLSIZE)
                       ~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 930, in __init__
    Pool.__init__(self, processes, initializer, initargs)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 215, in __init__
    self._repopulate_pool()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 306, in _repopulate_pool
    return self._repopulate_pool_static(self._ctx, self.Process,
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
                                        self._processes,
                                        ^^^^^^^^^^^^^^^^
    ...<3 lines>...
                                        self._maxtasksperchild,
                                        ^^^^^^^^^^^^^^^^^^^^^^^
                                        self._wrap_exception)
                                        ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.13/multiprocessing/pool.py", line 329, in _repopulate_pool_static
    w.start()
    ~~~~~~~^^
  File "/usr/lib/python3.13/multiprocessing/dummy/__init__.py", line 51, in start
    threading.Thread.start(self)
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib/python3.13/threading.py", line 973, in start
    _start_joinable_thread(self._bootstrap, handle=self._handle,
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           daemon=self.daemon)
                           ^^^^^^^^^^^^^^^^^^^
RuntimeError: can't start new thread
=================================== FAILURES ===================================
________________________________ test_streaming ________________________________

    def test_streaming():
        canary = b"this is my test" * 1000
        source = Stream(TestPerson("gbin@gootz.net"), BytesIO(canary))
        clients = [StreamingClient() for _ in range(50)]
>       Tee(source, clients).run()

tests/streaming_test.py:17: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../errbot/streaming.py:81: in run
    thread.start()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Thread(Thread-569 (streamer), stopped)>

    def start(self):
        """Start the thread's activity.
    
        It must be called at most once per thread object. It arranges for the
        object's run() method to be invoked in a separate thread of control.
    
        This method will raise a RuntimeError if called more than once on the
        same thread object.
    
        """
        if not self._initialized:
            raise RuntimeError("thread.__init__() not called")
    
        if self._started.is_set():
            raise RuntimeError("threads can only be started once")
    
        with _active_limbo_lock:
            _limbo[self] = self
        try:
            # Start joinable thread
>           _start_joinable_thread(self._bootstrap, handle=self._handle,
                                   daemon=self.daemon)
E                                  RuntimeError: can't start new thread

/usr/lib/python3.13/threading.py:973: RuntimeError
=============================== warnings summary ===============================
../../../errbot/utils.py:13
  /build/reproducible-path/errbot-6.2.0+ds/errbot/utils.py:13: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
    import pkg_resources

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/streaming_test.py::test_streaming - RuntimeError: can't start ne...
ERROR tests/commands_test.py::test_echo - SystemExit: -1
ERROR tests/commands_test.py::test_status_gc - SystemExit: -1
ERROR tests/commands_test.py::test_config_cycle - SystemExit: -1
ERROR tests/commands_test.py::test_apropos - SystemExit: -1
ERROR tests/commands_test.py::test_logtail - SystemExit: -1
ERROR tests/commands_test.py::test_history - SystemExit: -1
ERROR tests/commands_test.py::test_encoding_preservation - SystemExit: -1
ERROR tests/commands_test.py::test_webserver_webhook_test - SystemExit: -1
ERROR tests/commands_test.py::test_activate_reload_and_deactivate - SystemExi...
ERROR tests/commands_test.py::test_unblacklist_and_blacklist - SystemExit: -1
ERROR tests/commands_test.py::test_optional_prefix - SystemExit: -1
ERROR tests/commands_test.py::test_optional_prefix_re_cmd - SystemExit: -1
ERROR tests/commands_test.py::test_simple_match - SystemExit: -1
ERROR tests/commands_test.py::test_no_suggest_on_re_commands - SystemExit: -1
ERROR tests/commands_test.py::test_callback_no_command - SystemExit: -1
ERROR tests/commands_test.py::test_subcommands - SystemExit: -1
ERROR tests/commands_test.py::test_command_not_found_with_space_in_bot_prefix
ERROR tests/commands_test.py::test_mock_injection - SystemExit: -1
ERROR tests/commands_test.py::test_multiline_command - SystemExit: -1
ERROR tests/commands_test.py::test_plugin_info_command - SystemExit: -1
ERROR tests/core_plugins_test.py::test_help_is_still_here - SystemExit: -1
ERROR tests/core_plugins_test.py::test_echo_still_here - SystemExit: -1
ERROR tests/core_plugins_test.py::test_bot_prefix_replaced - SystemExit: -1
ERROR tests/core_test.py::test_admins_to_notify - SystemExit: -1
ERROR tests/core_test.py::test_admins_not_notified - SystemExit: -1
ERROR tests/dependencies_test.py::test_if_all_loaded_by_default - SystemExit: -1
ERROR tests/dependencies_test.py::test_single_dependency - SystemExit: -1
ERROR tests/dependencies_test.py::test_double_dependency - SystemExit: -1
ERROR tests/dependencies_test.py::test_dependency_retrieval - SystemExit: -1
ERROR tests/dependencies_test.py::test_direct_circular_dependency - SystemExi...
ERROR tests/dependencies_test.py::test_indirect_circular_dependency - SystemE...
ERROR tests/dependencies_test.py::test_chained_dependency - SystemExit: -1
ERROR tests/dynaplug_test.py::test_simple - SystemExit: -1
ERROR tests/dynaplug_test.py::test_arg - SystemExit: -1
ERROR tests/dynaplug_test.py::test_re - SystemExit: -1
ERROR tests/dynaplug_test.py::test_saw - SystemExit: -1
ERROR tests/dynaplug_test.py::test_clashing - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_list_flows - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_no_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_no_duplicate_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_secondary_autotrigger - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_manual_flow - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_manual_flow_with_or_without_hinting - Syst...
ERROR tests/flow_e2e_test.py::test_no_flyby_trigger_flow - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flow_only - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flow_only_help - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flows_stop - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_flows_kill - SystemExit: -1
ERROR tests/flow_e2e_test.py::test_room_flow - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_return - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_simple_name - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_prefix - SystemExit: -1
ERROR tests/i18n_test.py::test_i18n_suffix - SystemExit: -1
ERROR tests/link_test.py::test_linked_plugin_here - SystemExit: -1
ERROR tests/matchall_test.py::test_botmatch_correct - SystemExit: -1
ERROR tests/matchall_test.py::test_botmatch - SystemExit: -1
ERROR tests/mention_test.py::test_foreign_mention - SystemExit: -1
ERROR tests/mention_test.py::test_testbot_mention - SystemExit: -1
ERROR tests/mention_test.py::test_multiple_mentions - SystemExit: -1
ERROR tests/muc_test.py::test_plugin_methods - SystemExit: -1
ERROR tests/muc_test.py::test_create_join_leave_destroy_lifecycle - SystemExi...
ERROR tests/muc_test.py::test_occupants - SystemExit: -1
ERROR tests/muc_test.py::test_topic - SystemExit: -1
ERROR tests/muc_test.py::test_plugin_callbacks - SystemExit: -1
ERROR tests/muc_test.py::test_botcommands - SystemExit: -1
ERROR tests/multi_plugin_test.py::test_first - SystemExit: -1
ERROR tests/multi_plugin_test.py::test_second - SystemExit: -1
ERROR tests/plugin_config_fail_test.py::test_failed_config - SystemExit: -1
ERROR tests/plugin_config_test.py::test_failed_config - SystemExit: -1
ERROR tests/poller_test.py::test_delayed_hello - SystemExit: -1
ERROR tests/poller_test.py::test_delayed_hello_loop - SystemExit: -1
ERROR tests/syntax_test.py::test_nosyntax - SystemExit: -1
ERROR tests/syntax_test.py::test_syntax - SystemExit: -1
ERROR tests/syntax_test.py::test_re_syntax - SystemExit: -1
ERROR tests/syntax_test.py::test_arg_syntax - SystemExit: -1
ERROR tests/templates_test.py::test_templates_1 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_2 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_3 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_4 - SystemExit: -1
ERROR tests/templates_test.py::test_templates_5 - SystemExit: -1
ERROR tests/webhooks_test.py::test_not_configured_url_returns_404 - SystemExi...
ERROR tests/webhooks_test.py::test_webserver_plugin_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_trailing_no_slash_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_trailing_slash_also_ok - SystemExit: -1
ERROR tests/webhooks_test.py::test_json_is_automatically_decoded - SystemExit...
ERROR tests/webhooks_test.py::test_json_on_custom_url_is_automatically_decoded
ERROR tests/webhooks_test.py::test_post_form_on_webhook_without_form_param_is_automatically_decoded
ERROR tests/webhooks_test.py::test_post_form_on_webhook_with_custom_url_and_without_form_param_is_automatically_decoded
ERROR tests/webhooks_test.py::test_webhooks_with_form_parameter_decode_json_automatically
ERROR tests/webhooks_test.py::test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically
ERROR tests/webhooks_test.py::test_webhooks_with_raw_request - SystemExit: -1
ERROR tests/webhooks_test.py::test_webhooks_with_naked_decorator_raw_request
ERROR tests/webhooks_test.py::test_generate_certificate_creates_usable_cert
ERROR tests/webhooks_test.py::test_custom_headers_and_status_codes - SystemEx...
ERROR tests/webhooks_test.py::test_lambda_webhook - SystemExit: -1
====== 1 failed, 110 passed, 8 deselected, 1 warning, 96 errors in 18.79s ======
E: pybuild pybuild:389: test: plugin distutils failed with: exit code=1: cd /build/reproducible-path/errbot-6.2.0+ds/.pybuild/cpython3_3.13_errbot/build; python3.13 -m pytest -k "not test_broken_plugin and not test_backup and not test_plugin_cycle and not test_entrypoint_paths and not test_check_dependencies_requirements_file_all_installed"
	rm -fr -- /tmp/dh-xdg-rundir-HDwhIC0c
dh_auto_test: error: pybuild --test --test-pytest -i python{version} -p "3.12 3.13" returned exit code 13
make[1]: *** [debian/rules:24: override_dh_auto_test] Error 25
make[1]: Leaving directory '/build/reproducible-path/errbot-6.2.0+ds'
make: *** [debian/rules:17: binary] Error 2
dpkg-buildpackage: error: debian/rules binary subprocess returned exit status 2
I: copying local configuration
E: Failed autobuilding of package
I: unmounting dev/ptmx filesystem
I: unmounting dev/pts filesystem
I: unmounting dev/shm filesystem
I: unmounting proc filesystem
I: unmounting sys filesystem
I: cleaning the build env 
I: removing directory /srv/workspace/pbuilder/56873 and its subdirectories
Tue Jan 28 15:00:30 UTC 2025  W: No second build log, what happened?