aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/pybind11/tests/test_factory_constructors.py
blob: ffcce6fd4ddb36a48692b4fa2c977a1f58a55663 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
pre { line-height: 125%; margin: 0; }
td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight { background: #ffffff; }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2021  Symbiflow Authors
 *
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#ifndef FLAT_WIRE_MAP_H_
#define FLAT_WIRE_MAP_H_

#include "context.h"
#include "dynamic_bitarray.h"
#include "nextpnr_namespaces.h"
#include "nextpnr_types.h"

NEXTPNR_NAMESPACE_BEGIN

template <typename Value> class FlatTileWireMap
{
  public:
    std::pair<Value *, bool> emplace(const Context *ctx, WireId wire, const Value &value)
    {
        if (values_.empty()) {
            if (wire.tile == -1) {
                resize(ctx->chip_info->nodes.size());
            } else {
                resize(loc_info(ctx->chip_info, wire).wire_data.size());
            }
        }

        if (set_.get(wire.index)) {
            return std::make_pair(&values_[wire.index], false);
        } else {
            values_[wire.index] = value;
            set_.set(wire.index, true);
            return std::make_pair(&values_[wire.index], true);
        }
    }

    const Value &at(WireId wire) const
    {
        NPNR_ASSERT(!values_.empty());
        NPNR_ASSERT(set_.get(wire.index));
        return values_.at(wire.index);
    }

    void clear()
    {
        if (!values_.empty()) {
            set_.fill(false);
        }
    }

  private:
    void resize(size_t count)
    {
        set_.resize(count);
        set_.fill(false);
        values_.resize(count);
    }

    DynamicBitarray<> set_;
    std::vector<Value> values_;<
# -*- coding: utf-8 -*-
import pytest
import re

import env  # noqa: F401

from pybind11_tests import factory_constructors as m
from pybind11_tests.factory_constructors import tag
from pybind11_tests import ConstructorStats


def test_init_factory_basic():
    """Tests py::init_factory() wrapper around various ways of returning the object"""

    cstats = [
        ConstructorStats.get(c)
        for c in [m.TestFactory1, m.TestFactory2, m.TestFactory3]
    ]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    x1 = m.TestFactory1(tag.unique_ptr, 3)
    assert x1.value == "3"
    y1 = m.TestFactory1(tag.pointer)
    assert y1.value == "(empty)"
    z1 = m.TestFactory1("hi!")
    assert z1.value == "hi!"

    assert ConstructorStats.detail_reg_inst() == n_inst + 3

    x2 = m.TestFactory2(tag.move)
    assert x2.value == "(empty2)"
    y2 = m.TestFactory2(tag.pointer, 7)
    assert y2.value == "7"
    z2 = m.TestFactory2(tag.unique_ptr, "hi again")
    assert z2.value == "hi again"

    assert ConstructorStats.detail_reg_inst() == n_inst + 6

    x3 = m.TestFactory3(tag.shared_ptr)
    assert x3.value == "(empty3)"
    y3 = m.TestFactory3(tag.pointer, 42)
    assert y3.value == "42"
    z3 = m.TestFactory3("bye")
    assert z3.value == "bye"

    for null_ptr_kind in [tag.null_ptr, tag.null_unique_ptr, tag.null_shared_ptr]:
        with pytest.raises(TypeError) as excinfo:
            m.TestFactory3(null_ptr_kind)
        assert (
            str(excinfo.value) == "pybind11::init(): factory function returned nullptr"
        )

    assert [i.alive() for i in cstats] == [3, 3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 9

    del x1, y2, y3, z3
    assert [i.alive() for i in cstats] == [2, 2, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    del x2, x3, y1, z1, z2
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["3", "hi!"],
        ["7", "hi again"],
        ["42", "bye"],
    ]
    assert [i.default_constructions for i in cstats] == [1, 1, 1]


def test_init_factory_signature(msg):
    with pytest.raises(TypeError) as excinfo:
        m.TestFactory1("invalid", "constructor", "arguments")
    assert (
        msg(excinfo.value)
        == """
        __init__(): incompatible constructor arguments. The following argument types are supported:
            1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
            2. m.factory_constructors.TestFactory1(arg0: str)
            3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag)
            4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle)

        Invoked with: 'invalid', 'constructor', 'arguments'
    """  # noqa: E501 line too long
    )

    assert (
        msg(m.TestFactory1.__init__.__doc__)
        == """
        __init__(*args, **kwargs)
        Overloaded function.

        1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None

        2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None

        3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None

        4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None
    """  # noqa: E501 line too long
    )


def test_init_factory_casting():
    """Tests py::init_factory() wrapper with various upcasting and downcasting returns"""

    cstats = [
        ConstructorStats.get(c)
        for c in [m.TestFactory3, m.TestFactory4, m.TestFactory5]
    ]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    # Construction from derived references:
    a = m.TestFactory3(tag.pointer, tag.TF4, 4)
    assert a.value == "4"
    b = m.TestFactory3(tag.shared_ptr, tag.TF4, 5)
    assert b.value == "5"
    c = m.TestFactory3(tag.pointer, tag.TF5, 6)
    assert c.value == "6"
    d = m.TestFactory3(tag.shared_ptr, tag.TF5, 7)
    assert d.value == "7"

    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    # Shared a lambda with TF3:
    e = m.TestFactory4(tag.pointer, tag.TF4, 8)
    assert e.value == "8"

    assert ConstructorStats.detail_reg_inst() == n_inst + 5
    assert [i.alive() for i in cstats] == [5, 3, 2]

    del a
    assert [i.alive() for i in cstats] == [4, 2, 2]
    assert ConstructorStats.detail_reg_inst() == n_inst + 4

    del b, c, e
    assert [i.alive() for i in cstats] == [1, 0, 1]
    assert ConstructorStats.detail_reg_inst() == n_inst + 1

    del d
    assert [i.alive() for i in cstats] == [0, 0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["4", "5", "6", "7", "8"],
        ["4", "5", "8"],
        ["6", "7"],
    ]


def test_init_factory_alias():
    """Tests py::init_factory() wrapper with value conversions and alias types"""

    cstats = [m.TestFactory6.get_cstats(), m.TestFactory6.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    a = m.TestFactory6(tag.base, 1)
    assert a.get() == 1
    assert not a.has_alias()
    b = m.TestFactory6(tag.alias, "hi there")
    assert b.get() == 8
    assert b.has_alias()
    c = m.TestFactory6(tag.alias, 3)
    assert c.get() == 3
    assert c.has_alias()
    d = m.TestFactory6(tag.alias, tag.pointer, 4)
    assert d.get() == 4
    assert d.has_alias()
    e = m.TestFactory6(tag.base, tag.pointer, 5)
    assert e.get() == 5
    assert not e.has_alias()
    f = m.TestFactory6(tag.base, tag.alias, tag.pointer, 6)
    assert f.get() == 6
    assert f.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 6
    assert [i.alive() for i in cstats] == [6, 4]

    del a, b, e
    assert [i.alive() for i in cstats] == [3, 3]
    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    del f, c, d
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    class MyTest(m.TestFactory6):
        def __init__(self, *args):
            m.TestFactory6.__init__(self, *args)

        def get(self):
            return -5 + m.TestFactory6.get(self)

    # Return Class by value, moved into new alias:
    z = MyTest(tag.base, 123)
    assert z.get() == 118
    assert z.has_alias()

    # Return alias by value, moved into new alias:
    y = MyTest(tag.alias, "why hello!")
    assert y.get() == 5
    assert y.has_alias()

    # Return Class by pointer, moved into new alias then original destroyed:
    x = MyTest(tag.base, tag.pointer, 47)
    assert x.get() == 42
    assert x.has_alias()

    assert ConstructorStats.detail_reg_inst() == n_inst + 3
    assert [i.alive() for i in cstats] == [3, 3]
    del x, y, z
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["1", "8", "3", "4", "5", "6", "123", "10", "47"],
        ["hi there", "3", "4", "6", "move", "123", "why hello!", "move", "47"],
    ]


def test_init_factory_dual():
    """Tests init factory functions with dual main/alias factory functions"""
    from pybind11_tests.factory_constructors import TestFactory7

    cstats = [TestFactory7.get_cstats(), TestFactory7.get_alias_cstats()]
    cstats[0].alive()  # force gc
    n_inst = ConstructorStats.detail_reg_inst()

    class PythFactory7(TestFactory7):
        def get(self):
            return 100 + TestFactory7.get(self)

    a1 = TestFactory7(1)
    a2 = PythFactory7(2)
    assert a1.get() == 1
    assert a2.get() == 102
    assert not a1.has_alias()
    assert a2.has_alias()

    b1 = TestFactory7(tag.pointer, 3)
    b2 = PythFactory7(tag.pointer, 4)
    assert b1.get() == 3
    assert b2.get() == 104
    assert not b1.has_alias()
    assert b2.has_alias()

    c1 = TestFactory7(tag.mixed, 5)
    c2 = PythFactory7(tag.mixed, 6)
    assert c1.get() == 5
    assert c2.get() == 106
    assert not c1.has_alias()
    assert c2.has_alias()

    d1 = TestFactory7(tag.base, tag.pointer, 7)
    d2 = PythFactory7(tag.base, tag.pointer, 8)
    assert d1.get() == 7
    assert d2.get() == 108
    assert not d1.has_alias()
    assert d2.has_alias()

    # Both return an alias; the second multiplies the value by 10:
    e1 = TestFactory7(tag.alias, tag.pointer, 9)
    e2 = PythFactory7(tag.alias, tag.pointer, 10)
    assert e1.get() == 9
    assert e2.get() == 200
    assert e1.has_alias()
    assert e2.has_alias()

    f1 = TestFactory7(tag.shared_ptr, tag.base, 11)
    f2 = PythFactory7(tag.shared_ptr, tag.base, 12)
    assert f1.get() == 11
    assert f2.get() == 112
    assert not f1.has_alias()
    assert f2.has_alias()

    g1 = TestFactory7(tag.shared_ptr, tag.invalid_base, 13)
    assert g1.get() == 13
    assert not g1.has_alias()
    with pytest.raises(TypeError) as excinfo:
        PythFactory7(tag.shared_ptr, tag.invalid_base, 14)
    assert (
        str(excinfo.value)
        == "pybind11::init(): construction failed: returned holder-wrapped instance is not an "
        "alias instance"
    )

    assert [i.alive() for i in cstats] == [13, 7]
    assert ConstructorStats.detail_reg_inst() == n_inst + 13

    del a1, a2, b1, d1, e1, e2
    assert [i.alive() for i in cstats] == [7, 4]
    assert ConstructorStats.detail_reg_inst() == n_inst + 7
    del b2, c1, c2, d2, f1, f2, g1
    assert [i.alive() for i in cstats] == [0, 0]
    assert ConstructorStats.detail_reg_inst() == n_inst

    assert [i.values() for i in cstats] == [
        ["1", "2", "3", "4", "5", "6", "7", "8", "9", "100", "11", "12", "13", "14"],
        ["2", "4", "6", "8", "9", "100", "12"],
    ]


def test_no_placement_new(capture):
    """Prior to 2.2, `py::init<...>` relied on the type supporting placement
    new; this tests a class without placement new support."""
    with capture:
        a = m.NoPlacementNew(123)

    found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))
    assert found
    assert a.i == 123
    with capture:
        del a
        pytest.gc_collect()
    assert capture == "operator delete called on " + found.group(1)

    with capture:
        b = m.NoPlacementNew()

    found = re.search(r"^operator new called, returning (\d+)\n$", str(capture))
    assert found
    assert b.i == 100
    with capture:
        del b
        pytest.gc_collect()
    assert capture == "operator delete called on " + found.group(1)


def test_multiple_inheritance():
    class MITest(m.TestFactory1, m.TestFactory2):
        def __init__(self):
            m.TestFactory1.__init__(self, tag.unique_ptr, 33)
            m.TestFactory2.__init__(self, tag.move)

    a = MITest()
    assert m.TestFactory1.value.fget(a) == "33"
    assert m.TestFactory2.value.fget(a) == "(empty2)"


def create_and_destroy(*args):
    a = m.NoisyAlloc(*args)
    print("---")
    del a
    pytest.gc_collect()


def strip_comments(s):
    return re.sub(r"\s+#.*", "", s)


def test_reallocation_a(capture, msg):
    """When the constructor is overloaded, previous overloads can require a preallocated value.
    This test makes sure that such preallocated values only happen when they might be necessary,
    and that they are deallocated properly."""

    pytest.gc_collect()

    with capture:
        create_and_destroy(1)
    assert (
        msg(capture)
        == """
        noisy new
        noisy placement new
        NoisyAlloc(int 1)
        ---
        ~NoisyAlloc()
        noisy delete
    """
    )


def test_reallocation_b(capture, msg):
    with capture:
        create_and_destroy(1.5)
    assert msg(capture) == strip_comments(
        """
        noisy new               # allocation required to attempt first overload
        noisy delete            # have to dealloc before considering factory init overload
        noisy new               # pointer factory calling "new", part 1: allocation
        NoisyAlloc(double 1.5)  # ... part two, invoking constructor
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


def test_reallocation_c(capture, msg):
    with capture:
        create_and_destroy(2, 3)
    assert msg(capture) == strip_comments(
        """
        noisy new          # pointer factory calling "new", allocation
        NoisyAlloc(int 2)  # constructor
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


def test_reallocation_d(capture, msg):
    with capture:
        create_and_destroy(2.5, 3)
    assert msg(capture) == strip_comments(
        """
        NoisyAlloc(double 2.5)  # construction (local func variable: operator_new not called)
        noisy new               # return-by-value "new" part 1: allocation
        ~NoisyAlloc()           # moved-away local func variable destruction
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


def test_reallocation_e(capture, msg):
    with capture:
        create_and_destroy(3.5, 4.5)
    assert msg(capture) == strip_comments(
        """
        noisy new               # preallocation needed before invoking placement-new overload
        noisy placement new     # Placement new
        NoisyAlloc(double 3.5)  # construction
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


def test_reallocation_f(capture, msg):
    with capture:
        create_and_destroy(4, 0.5)
    assert msg(capture) == strip_comments(
        """
        noisy new          # preallocation needed before invoking placement-new overload
        noisy delete       # deallocation of preallocated storage
        noisy new          # Factory pointer allocation
        NoisyAlloc(int 4)  # factory pointer construction
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


def test_reallocation_g(capture, msg):
    with capture:
        create_and_destroy(5, "hi")
    assert msg(capture) == strip_comments(
        """
        noisy new            # preallocation needed before invoking first placement new
        noisy delete         # delete before considering new-style constructor
        noisy new            # preallocation for second placement new
        noisy placement new  # Placement new in the second placement new overload
        NoisyAlloc(int 5)    # construction
        ---
        ~NoisyAlloc()  # Destructor
        noisy delete   # operator delete
    """
    )


@pytest.mark.skipif("env.PY2")
def test_invalid_self():
    """Tests invocation of the pybind-registered base class with an invalid `self` argument.  You
    can only actually do this on Python 3: Python 2 raises an exception itself if you try."""

    class NotPybindDerived(object):
        pass

    # Attempts to initialize with an invalid type passed as `self`:
    class BrokenTF1(m.TestFactory1):
        def __init__(self, bad):
            if bad == 1:
                a = m.TestFactory2(tag.pointer, 1)
                m.TestFactory1.__init__(a, tag.pointer)
            elif bad == 2:
                a = NotPybindDerived()
                m.TestFactory1.__init__(a, tag.pointer)

    # Same as above, but for a class with an alias:
    class BrokenTF6(m.TestFactory6):
        def __init__(self, bad):
            if bad == 1:
                a = m.TestFactory2(tag.pointer, 1)
                m.TestFactory6.__init__(a, tag.base, 1)
            elif bad == 2:
                a = m.TestFactory2(tag.pointer, 1)
                m.TestFactory6.__init__(a, tag.alias, 1)
            elif bad == 3:
                m.TestFactory6.__init__(
                    NotPybindDerived.__new__(NotPybindDerived), tag.base, 1
                )
            elif bad == 4:
                m.TestFactory6.__init__(
                    NotPybindDerived.__new__(NotPybindDerived), tag.alias, 1
                )

    for arg in (1, 2):
        with pytest.raises(TypeError) as excinfo:
            BrokenTF1(arg)
        assert (
            str(excinfo.value)
            == "__init__(self, ...) called with invalid `self` argument"
        )

    for arg in (1, 2, 3, 4):
        with pytest.raises(TypeError) as excinfo:
            BrokenTF6(arg)
        assert (
            str(excinfo.value)
            == "__init__(self, ...) called with invalid `self` argument"
        )