##// END OF EJS Templates
interfaces: make the `peer` mixin not a Protocol to fix Python 3.10 failures...
interfaces: make the `peer` mixin not a Protocol to fix Python 3.10 failures I can't find any documentation on this, but it appears that Protocol class attributes don't get inherited in subclasses that explicitly subclass a Protocol until Python 3.11, which caused a ton of failures in CI on macOS and Windows (which both test using Python 3.9). The problem started with 1df97507c6b8, and typically manifested as most tests failing to access `ui` on various `peer` classes. Here's a short proof of concept: from __future__ import annotations from typing import ( Protocol, ) class peer(Protocol): limitedarguments: bool = False def __init__(self, arg1, arg2, remotehidden: bool = False) -> None: self.arg1 = arg1 self.arg2 = arg2 class subclass(peer): def __init__(self, arg1, arg2): super(subclass, self).__init__(arg1, arg2, False) sub = subclass(1, 2) print("sub.arg1 is %r" % sub.arg1) When run with Python 3.8.10, 3.9.13, and 3.10.11, the result is: $ py -3.8 prot-test.py Traceback (most recent call last): File "prot-test.py", line 20, in <module> print("sub.arg1 is %r" % sub.arg1) AttributeError: 'subclass' object has no attribute 'arg1' On Python 3.11.9, 3.12.7, and 3.13.0, the result is: $ py -3.11 ../prot-test.py sub.arg1 is 1 Explicitly adding annotations to `peer` like `limitedarguments` didn't help.

File last commit:

r52599:541292a0 default
r53403:199b0e62 default
Show More
flake.nix
177 lines | 4.8 KiB | text/x-nix | NixLexer
# flake.nix - Nix-defined package and devel env for the Mercurial project.
#
# Copyright 2021-2023 Pacien TRAN-GIRARD <pacien.trangirard@pacien.net>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
# Usage summary, from the root of this repository:
#
# Enter a shell with development tools:
# nix develop 'hg+file:.?dir=contrib/nix'
#
# Running mercurial:
# nix run 'hg+file:.?dir=contrib/nix' -- version
#
# Running the test suite in a sandbox:
# nix build 'hg+file:.?dir=contrib/nix#mercurial-tests' -L
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
nixpkgs-black.url = "github:NixOS/nixpkgs/c7cb72b0"; # black 20.8b1
# rust-overlay.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
flaky-utils.url = "git+https://cgit.pacien.net/libs/flaky-utils";
};
outputs = {
self
, nixpkgs
, nixpkgs-black
# , rust-overlay
, flake-utils
, flaky-utils
}:
flake-utils.lib.eachDefaultSystem (system:
let
# overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs { inherit system; };
# We're in the contrib/nix sub-directory.
src = ../..;
# For snapshots, to satisfy extension minimum version requirements.
dummyVersion = "99.99";
pin = {
# The test suite has issues with the latest/current versions of Python.
# Use an older recommended version instead, matching the CI.
python = pkgs.python39;
# The project uses a pinned version (rust/clippy.toml) for compiling,
# but uses formatter features from nightly.
# TODO: make cargo use the formatter from nightly automatically
# (not supported by rustup/cargo yet? workaround?)
# rustPlatform = pkgs.rust-bin.stable."1.79.0".default;
# rustPlatformFormatter = pkgs.rust-bin.nightly."2023-04-20".default;
# The CI uses an old version of the Black code formatter,
# itself depending on old Python libraries.
# The formatting rules have changed in more recent versions.
inherit (import nixpkgs-black { inherit system; }) black;
};
in rec {
apps.mercurial = apps.mercurial-rust;
apps.default = apps.mercurial;
apps.mercurial-c = flake-utils.lib.mkApp {
drv = packages.mercurial-c;
};
apps.mercurial-rust = flake-utils.lib.mkApp {
drv = packages.mercurial-rust;
};
packages.mercurial = packages.mercurial-rust;
packages.default = packages.mercurial;
packages.mercurial-c = pin.python.pkgs.buildPythonApplication {
format = "other";
pname = "mercurial";
version = "SNAPSHOT";
passthru.exePath = "/bin/hg";
inherit src;
postPatch = ''
echo 'version = b"${toString dummyVersion}"' \
> mercurial/__version__.py
patchShebangs .
for f in **/*.{py,c,t}; do
# not only used in shebangs
substituteAllInPlace "$f" '/bin/sh' '${pkgs.stdenv.shell}'
done
'';
buildInputs = with pin.python.pkgs; [
docutils
];
nativeBuildInputs = with pkgs; [
gettext
installShellFiles
];
makeFlags = [
"PREFIX=$(out)"
];
buildPhase = ''
make local
'';
# Test suite is huge ; run on-demand in a separate package instead.
doCheck = false;
};
packages.mercurial-rust = packages.mercurial-c.overrideAttrs (super: {
cargoRoot = "rust";
cargoDeps = pkgs.rustPlatform.importCargoLock {
lockFile = "${src}/rust/Cargo.lock";
};
nativeBuildInputs = (super.nativeBuildInputs or []) ++ (
with pkgs.rustPlatform; [
cargoSetupHook
rust.cargo
rust.rustc
]
);
makeFlags = (super.makeFlags or []) ++ [
"PURE=--rust"
];
});
packages.mercurial-tests = pkgs.stdenv.mkDerivation {
pname = "mercurial-tests";
version = "SNAPSHOT";
inherit src;
buildInputs = with pkgs; [
pin.python
pin.black
unzip
which
sqlite
];
postPatch = (packages.mercurial.postPatch or "") + ''
# * paths emitted by our wrapped hg look like ..hg-wrapped-wrapped
# * 'hg' is a wrapper; don't run using python directly
for f in **/*.t; do
substituteInPlace 2>/dev/null "$f" \
--replace '*/hg:' '*/*hg*:' \
--replace '"$PYTHON" "$BINDIR"/hg' '"$BINDIR"/hg'
done
'';
buildPhase = ''
export HGTEST_REAL_HG="${packages.mercurial}/bin/hg"
export HGMODULEPOLICY="rust+c"
export HGTESTFLAGS="--blacklist blacklists/nix"
make check 2>&1 | tee "$out"
'';
};
devShell = flaky-utils.lib.mkDevShell {
inherit pkgs;
tools = [
pin.python
pin.black
];
};
});
}