Merge pull request #9418 from SomberNight/202501_bump_min_python
bump min python to 3.10
This commit is contained in:
18
.cirrus.yml
18
.cirrus.yml
@@ -10,8 +10,6 @@ task:
|
|||||||
TOXENV: py3
|
TOXENV: py3
|
||||||
ELECTRUM_PYTHON_NAME: python3
|
ELECTRUM_PYTHON_NAME: python3
|
||||||
matrix:
|
matrix:
|
||||||
- env:
|
|
||||||
ELECTRUM_PYTHON_VERSION: 3.9
|
|
||||||
- env:
|
- env:
|
||||||
ELECTRUM_PYTHON_VERSION: 3.10
|
ELECTRUM_PYTHON_VERSION: 3.10
|
||||||
- env:
|
- env:
|
||||||
@@ -85,11 +83,11 @@ task:
|
|||||||
locale_script:
|
locale_script:
|
||||||
- contrib/push_locale
|
- contrib/push_locale
|
||||||
env:
|
env:
|
||||||
ELECTRUM_IMAGE: python:3.9
|
ELECTRUM_IMAGE: python:3.10
|
||||||
ELECTRUM_REQUIREMENTS_CI: contrib/requirements/requirements-ci.txt
|
ELECTRUM_REQUIREMENTS_CI: contrib/requirements/requirements-ci.txt
|
||||||
# in addition, crowdin_api_key is set as an "override" in https://cirrus-ci.com/settings/...
|
# in addition, crowdin_api_key is set as an "override" in https://cirrus-ci.com/settings/...
|
||||||
depends_on:
|
depends_on:
|
||||||
- "unittests: Tox Python 3.9"
|
- "unittests: Tox Python 3.10"
|
||||||
only_if: $CIRRUS_BRANCH == 'master'
|
only_if: $CIRRUS_BRANCH == 'master'
|
||||||
|
|
||||||
task:
|
task:
|
||||||
@@ -156,7 +154,7 @@ task:
|
|||||||
flake8_script:
|
flake8_script:
|
||||||
- flake8 . --count --select="$ELECTRUM_LINTERS" --ignore="$ELECTRUM_LINTERS_IGNORE" --show-source --statistics --exclude "*_pb2.py,electrum/_vendor/"
|
- flake8 . --count --select="$ELECTRUM_LINTERS" --ignore="$ELECTRUM_LINTERS_IGNORE" --show-source --statistics --exclude "*_pb2.py,electrum/_vendor/"
|
||||||
env:
|
env:
|
||||||
ELECTRUM_IMAGE: python:3.9
|
ELECTRUM_IMAGE: python:3.10
|
||||||
ELECTRUM_REQUIREMENTS: contrib/requirements/requirements.txt
|
ELECTRUM_REQUIREMENTS: contrib/requirements/requirements.txt
|
||||||
matrix:
|
matrix:
|
||||||
- name: "linter: Flake8 Mandatory"
|
- name: "linter: Flake8 Mandatory"
|
||||||
@@ -212,7 +210,7 @@ task:
|
|||||||
CIRRUS_WORKING_DIR: /opt/wine64/drive_c/electrum
|
CIRRUS_WORKING_DIR: /opt/wine64/drive_c/electrum
|
||||||
CIRRUS_DOCKER_CONTEXT: contrib/build-wine
|
CIRRUS_DOCKER_CONTEXT: contrib/build-wine
|
||||||
depends_on:
|
depends_on:
|
||||||
- "unittests: Tox Python 3.9"
|
- "unittests: Tox Python 3.10"
|
||||||
|
|
||||||
task:
|
task:
|
||||||
name: "build: Android (QML $APK_ARCH)"
|
name: "build: Android (QML $APK_ARCH)"
|
||||||
@@ -246,7 +244,7 @@ task:
|
|||||||
binaries_artifacts:
|
binaries_artifacts:
|
||||||
path: "dist/*"
|
path: "dist/*"
|
||||||
depends_on:
|
depends_on:
|
||||||
- "unittests: Tox Python 3.9"
|
- "unittests: Tox Python 3.10"
|
||||||
|
|
||||||
## mac build disabled, as Cirrus CI no longer supports Intel-based mac builds
|
## mac build disabled, as Cirrus CI no longer supports Intel-based mac builds
|
||||||
#task:
|
#task:
|
||||||
@@ -309,7 +307,7 @@ task:
|
|||||||
env:
|
env:
|
||||||
CIRRUS_DOCKER_CONTEXT: contrib/build-linux/appimage
|
CIRRUS_DOCKER_CONTEXT: contrib/build-linux/appimage
|
||||||
depends_on:
|
depends_on:
|
||||||
- "unittests: Tox Python 3.9"
|
- "unittests: Tox Python 3.10"
|
||||||
|
|
||||||
task:
|
task:
|
||||||
container:
|
container:
|
||||||
@@ -332,12 +330,12 @@ task:
|
|||||||
env:
|
env:
|
||||||
OMIT_UNCLEAN_FILES: 1
|
OMIT_UNCLEAN_FILES: 1
|
||||||
depends_on:
|
depends_on:
|
||||||
- "unittests: Tox Python 3.9"
|
- "unittests: Tox Python 3.10"
|
||||||
|
|
||||||
task:
|
task:
|
||||||
name: "check submodules"
|
name: "check submodules"
|
||||||
container:
|
container:
|
||||||
image: python:3.9
|
image: python:3.10
|
||||||
cpu: 1
|
cpu: 1
|
||||||
memory: 1G
|
memory: 1G
|
||||||
fetch_script:
|
fetch_script:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
```
|
```
|
||||||
Licence: MIT Licence
|
Licence: MIT Licence
|
||||||
Author: Thomas Voegtlin
|
Author: Thomas Voegtlin
|
||||||
Language: Python (>= 3.8)
|
Language: Python (>= 3.10)
|
||||||
Homepage: https://electrum.org/
|
Homepage: https://electrum.org/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM debian:bullseye@sha256:43ef0c6c3585d5b406caa7a0f232ff5a19c1402aeb415f68bcd1cf9d10180af8
|
FROM debian:bookworm@sha256:b877a1a3fdf02469440f1768cf69c9771338a875b7add5e80c45b756c92ac20a
|
||||||
|
|
||||||
ENV LC_ALL=C.UTF-8 LANG=C.UTF-8
|
ENV LC_ALL=C.UTF-8 LANG=C.UTF-8
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
@@ -11,7 +11,6 @@ RUN apt-get update -q && \
|
|||||||
python3-pip \
|
python3-pip \
|
||||||
python3-setuptools \
|
python3-setuptools \
|
||||||
python3-venv \
|
python3-venv \
|
||||||
faketime \
|
|
||||||
&& \
|
&& \
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
|
|||||||
@@ -6,21 +6,20 @@ PROJECT_ROOT="$(dirname "$(readlink -e "$0")")/../../.."
|
|||||||
CONTRIB="$PROJECT_ROOT/contrib"
|
CONTRIB="$PROJECT_ROOT/contrib"
|
||||||
CONTRIB_SDIST="$CONTRIB/build-linux/sdist"
|
CONTRIB_SDIST="$CONTRIB/build-linux/sdist"
|
||||||
DISTDIR="$PROJECT_ROOT/dist"
|
DISTDIR="$PROJECT_ROOT/dist"
|
||||||
|
BUILDDIR="$CONTRIB_SDIST/build"
|
||||||
LOCALE="$PROJECT_ROOT/electrum/locale"
|
LOCALE="$PROJECT_ROOT/electrum/locale"
|
||||||
|
|
||||||
. "$CONTRIB"/build_tools_util.sh
|
. "$CONTRIB"/build_tools_util.sh
|
||||||
|
|
||||||
git -C "$PROJECT_ROOT" rev-parse 2>/dev/null || fail "Building outside a git clone is not supported."
|
git -C "$PROJECT_ROOT" rev-parse 2>/dev/null || fail "Building outside a git clone is not supported."
|
||||||
|
|
||||||
# note that at least py3.7 is needed, to have https://bugs.python.org/issue30693
|
rm -rf "$BUILDDIR"
|
||||||
|
mkdir -p "$BUILDDIR" "$DISTDIR"
|
||||||
|
|
||||||
python3 --version || fail "python interpreter not found"
|
python3 --version || fail "python interpreter not found"
|
||||||
|
|
||||||
break_legacy_easy_install
|
break_legacy_easy_install
|
||||||
|
|
||||||
# upgrade to modern pip so that it knows the flags we need.
|
|
||||||
# (make_packages.sh will later install a pinned version of pip in a venv)
|
|
||||||
python3 -m pip install --upgrade pip
|
|
||||||
|
|
||||||
rm -rf "$PROJECT_ROOT/packages/"
|
rm -rf "$PROJECT_ROOT/packages/"
|
||||||
if ([ "$OMIT_UNCLEAN_FILES" != 1 ]); then
|
if ([ "$OMIT_UNCLEAN_FILES" != 1 ]); then
|
||||||
"$CONTRIB"/make_packages.sh || fail "make_packages failed"
|
"$CONTRIB"/make_packages.sh || fail "make_packages failed"
|
||||||
@@ -51,16 +50,32 @@ fi
|
|||||||
|
|
||||||
# note: .zip sdists would not be reproducible due to https://bugs.python.org/issue40963
|
# note: .zip sdists would not be reproducible due to https://bugs.python.org/issue40963
|
||||||
if ([ "$OMIT_UNCLEAN_FILES" = 1 ]); then
|
if ([ "$OMIT_UNCLEAN_FILES" = 1 ]); then
|
||||||
PY_DISTDIR="dist/_sourceonly" # The DISTDIR variable of this script is only used to find where the output is *finally* placed.
|
PY_DISTDIR="$BUILDDIR/dist1/_sourceonly" # The DISTDIR variable of this script is only used to find where the output is *finally* placed.
|
||||||
else
|
else
|
||||||
PY_DISTDIR="dist"
|
PY_DISTDIR="$BUILDDIR/dist1"
|
||||||
fi
|
fi
|
||||||
TZ=UTC faketime -f '2000-11-11 11:11:11' python3 setup.py --quiet sdist --format=gztar --dist-dir="$PY_DISTDIR"
|
# build initial tar.gz
|
||||||
if ([ "$OMIT_UNCLEAN_FILES" = 1 ]); then
|
python3 setup.py --quiet sdist --format=gztar --dist-dir="$PY_DISTDIR"
|
||||||
|
|
||||||
VERSION=$("$CONTRIB"/print_electrum_version.py)
|
VERSION=$("$CONTRIB"/print_electrum_version.py)
|
||||||
mv "dist/_sourceonly/Electrum-$VERSION.tar.gz" "dist/Electrum-sourceonly-$VERSION.tar.gz"
|
if ([ "$OMIT_UNCLEAN_FILES" = 1 ]); then
|
||||||
|
FINAL_DISTNAME="Electrum-sourceonly-$VERSION.tar.gz"
|
||||||
|
else
|
||||||
|
FINAL_DISTNAME="Electrum-$VERSION.tar.gz"
|
||||||
|
fi
|
||||||
|
if ([ "$OMIT_UNCLEAN_FILES" = 1 ]); then
|
||||||
|
mv "$PY_DISTDIR/Electrum-$VERSION.tar.gz" "$PY_DISTDIR/../$FINAL_DISTNAME"
|
||||||
rmdir "$PY_DISTDIR"
|
rmdir "$PY_DISTDIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# the initial tar.gz is not reproducible, see https://github.com/pypa/setuptools/issues/2133
|
||||||
|
# so we untar, fix timestamps, and then re-tar
|
||||||
|
mkdir -p "$BUILDDIR/dist2"
|
||||||
|
cd "$BUILDDIR/dist2"
|
||||||
|
tar -xzf "$BUILDDIR/dist1/$FINAL_DISTNAME"
|
||||||
|
find -exec touch -h -d '2000-11-11T11:11:11+00:00' {} +
|
||||||
|
GZIP=-n tar --sort=name -czf "$FINAL_DISTNAME" "Electrum-$VERSION/"
|
||||||
|
mv "$FINAL_DISTNAME" "$DISTDIR/$FINAL_DISTNAME"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ contrib=$(dirname "$0")
|
|||||||
|
|
||||||
# note: we should not use a higher version of python than what the binaries bundle
|
# note: we should not use a higher version of python than what the binaries bundle
|
||||||
if [[ ! "$SYSTEM_PYTHON" ]] ; then
|
if [[ ! "$SYSTEM_PYTHON" ]] ; then
|
||||||
SYSTEM_PYTHON=$(which python3.8) || printf ""
|
SYSTEM_PYTHON=$(which python3.10) || printf ""
|
||||||
else
|
else
|
||||||
SYSTEM_PYTHON=$(which $SYSTEM_PYTHON) || printf ""
|
SYSTEM_PYTHON=$(which $SYSTEM_PYTHON) || printf ""
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ from .network import Network
|
|||||||
from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare, InvalidPassword)
|
from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare, InvalidPassword)
|
||||||
from .invoices import PR_PAID, PR_EXPIRED
|
from .invoices import PR_PAID, PR_EXPIRED
|
||||||
from .util import log_exceptions, ignore_exceptions, randrange, OldTaskGroup, UserFacingException, JsonRPCError
|
from .util import log_exceptions, ignore_exceptions, randrange, OldTaskGroup, UserFacingException, JsonRPCError
|
||||||
from .util import EventListener, event_listener, traceback_format_exception
|
from .util import EventListener, event_listener
|
||||||
from .wallet import Wallet, Abstract_Wallet
|
from .wallet import Wallet, Abstract_Wallet
|
||||||
from .storage import WalletStorage
|
from .storage import WalletStorage
|
||||||
from .wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished
|
from .wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished
|
||||||
@@ -264,7 +264,7 @@ class AuthenticatedServer(Logger):
|
|||||||
'message': "internal error while executing RPC",
|
'message': "internal error while executing RPC",
|
||||||
'data': {
|
'data': {
|
||||||
"exception": repr(e),
|
"exception": repr(e),
|
||||||
"traceback": "".join(traceback_format_exception(e)),
|
"traceback": "".join(traceback.format_exception(e)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return web.json_response(response)
|
return web.json_response(response)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ from concurrent import futures
|
|||||||
import copy
|
import copy
|
||||||
import functools
|
import functools
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
from contextlib import nullcontext
|
||||||
|
|
||||||
import aiorpcx
|
import aiorpcx
|
||||||
from aiorpcx import ignore_after, NetAddress
|
from aiorpcx import ignore_after, NetAddress
|
||||||
@@ -47,7 +48,7 @@ from . import util
|
|||||||
from .util import (log_exceptions, ignore_exceptions, OldTaskGroup,
|
from .util import (log_exceptions, ignore_exceptions, OldTaskGroup,
|
||||||
bfh, make_aiohttp_session, send_exception_to_crash_reporter,
|
bfh, make_aiohttp_session, send_exception_to_crash_reporter,
|
||||||
is_hash256_str, is_non_negative_integer, MyEncoder, NetworkRetryManager,
|
is_hash256_str, is_non_negative_integer, MyEncoder, NetworkRetryManager,
|
||||||
nullcontext, error_text_str_to_safe_str)
|
error_text_str_to_safe_str)
|
||||||
from .bitcoin import COIN, DummyAddress, DummyAddressUsedInTxException
|
from .bitcoin import COIN, DummyAddress, DummyAddressUsedInTxException
|
||||||
from . import constants
|
from . import constants
|
||||||
from . import blockchain
|
from . import blockchain
|
||||||
|
|||||||
@@ -127,10 +127,7 @@ class Plugins(DaemonThread):
|
|||||||
# sys.modules needs to be modified for relative imports to work
|
# sys.modules needs to be modified for relative imports to work
|
||||||
# see https://stackoverflow.com/a/50395128
|
# see https://stackoverflow.com/a/50395128
|
||||||
sys.modules[path] = module
|
sys.modules[path] = module
|
||||||
if sys.version_info >= (3, 10):
|
|
||||||
spec.loader.exec_module(module)
|
spec.loader.exec_module(module)
|
||||||
else:
|
|
||||||
module = spec.loader.load_module(path)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f"Error pre-loading {path}: {repr(e)}") from e
|
raise Exception(f"Error pre-loading {path}: {repr(e)}") from e
|
||||||
return module
|
return module
|
||||||
@@ -209,12 +206,8 @@ class Plugins(DaemonThread):
|
|||||||
if name in self.external_plugin_metadata:
|
if name in self.external_plugin_metadata:
|
||||||
raise Exception(f"duplicate plugins for name={name}")
|
raise Exception(f"duplicate plugins for name={name}")
|
||||||
module_path = f'electrum_external_plugins.{name}'
|
module_path = f'electrum_external_plugins.{name}'
|
||||||
if sys.version_info >= (3, 10):
|
|
||||||
spec = zipfile.find_spec(name)
|
spec = zipfile.find_spec(name)
|
||||||
module = self.exec_module_from_spec(spec, module_path)
|
module = self.exec_module_from_spec(spec, module_path)
|
||||||
else:
|
|
||||||
module = zipfile.load_module(name)
|
|
||||||
sys.modules[module_path] = module
|
|
||||||
d = module.__dict__
|
d = module.__dict__
|
||||||
gui_good = self.gui_name in d.get('available_for', [])
|
gui_good = self.gui_name in d.get('available_for', [])
|
||||||
if not gui_good:
|
if not gui_good:
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ from functools import partial
|
|||||||
from abc import abstractmethod, ABC
|
from abc import abstractmethod, ABC
|
||||||
import socket
|
import socket
|
||||||
import enum
|
import enum
|
||||||
|
from contextlib import nullcontext
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -2067,35 +2068,6 @@ def test_read_write_permissions(path) -> None:
|
|||||||
raise IOError('echo sanity-check failed')
|
raise IOError('echo sanity-check failed')
|
||||||
|
|
||||||
|
|
||||||
class nullcontext:
|
|
||||||
"""Context manager that does no additional processing.
|
|
||||||
This is a ~backport of contextlib.nullcontext from Python 3.10
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, enter_result=None):
|
|
||||||
self.enter_result = enter_result
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self.enter_result
|
|
||||||
|
|
||||||
def __exit__(self, *excinfo):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def __aenter__(self):
|
|
||||||
return self.enter_result
|
|
||||||
|
|
||||||
async def __aexit__(self, *excinfo):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def traceback_format_exception(exc: BaseException) -> Sequence[str]:
|
|
||||||
"""Compatibility wrapper for stdlib traceback.format_exception using python 3.10+ API."""
|
|
||||||
if sys.version_info[:3] >= (3, 10):
|
|
||||||
return traceback.format_exception(exc)
|
|
||||||
else:
|
|
||||||
return traceback.format_exception(type(exc), value=exc, tb=exc.__traceback__)
|
|
||||||
|
|
||||||
|
|
||||||
class classproperty(property):
|
class classproperty(property):
|
||||||
"""~read-only class-level @property
|
"""~read-only class-level @property
|
||||||
from https://stackoverflow.com/a/13624858 by denis-ryzhkov
|
from https://stackoverflow.com/a/13624858 by denis-ryzhkov
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
MIN_PYTHON_VERSION = "3.8.0" # FIXME duplicated from setup.py
|
MIN_PYTHON_VERSION = "3.10.0" # FIXME duplicated from setup.py
|
||||||
_min_python_version_tuple = tuple(map(int, (MIN_PYTHON_VERSION.split("."))))
|
_min_python_version_tuple = tuple(map(int, (MIN_PYTHON_VERSION.split("."))))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -12,7 +12,7 @@ import subprocess
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
from setuptools.command.install import install
|
from setuptools.command.install import install
|
||||||
|
|
||||||
MIN_PYTHON_VERSION = "3.8.0"
|
MIN_PYTHON_VERSION = "3.10.0"
|
||||||
_min_python_version_tuple = tuple(map(int, (MIN_PYTHON_VERSION.split("."))))
|
_min_python_version_tuple = tuple(map(int, (MIN_PYTHON_VERSION.split("."))))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ from unittest import SkipTest
|
|||||||
|
|
||||||
from PyQt6.QtCore import QCoreApplication, QMetaObject, Qt, pyqtSlot, QObject
|
from PyQt6.QtCore import QCoreApplication, QMetaObject, Qt, pyqtSlot, QObject
|
||||||
|
|
||||||
from electrum.util import traceback_format_exception
|
|
||||||
|
|
||||||
|
|
||||||
class TestQCoreApplication(QCoreApplication):
|
class TestQCoreApplication(QCoreApplication):
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
@@ -78,7 +76,7 @@ def qt_test(func):
|
|||||||
if not res:
|
if not res:
|
||||||
self._e = Exception('testcase timed out')
|
self._e = Exception('testcase timed out')
|
||||||
if self._e:
|
if self._e:
|
||||||
print("".join(traceback_format_exception(self._e)))
|
print("".join(traceback.format_exception(self._e)))
|
||||||
# deallocate stored exception from qt thread otherwise we SEGV garbage collector
|
# deallocate stored exception from qt thread otherwise we SEGV garbage collector
|
||||||
# instead, re-create using the exception message, special casing AssertionError and SkipTest
|
# instead, re-create using the exception message, special casing AssertionError and SkipTest
|
||||||
e = None
|
e = None
|
||||||
|
|||||||
Reference in New Issue
Block a user