diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 0b25712..334b523 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -8,21 +8,17 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: ['3.5', '3.6', '3.7', '3.8', '3.9', '3.10', 'pypy3'] + python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy3.9'] os: [ubuntu-latest, windows-latest, macOS-latest] exclude: - os: macOS-latest - python-version: '3.5' - - os: macOS-latest - python-version: '3.6' - - os: macOS-latest - python-version: 'pypy3' + python-version: 'pypy3.9' fail-fast: false timeout-minutes: 3 steps: - uses: actions/checkout@v2 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} architecture: x64 @@ -35,7 +31,7 @@ jobs: PYTHONPATH: . run: | pip install pytest - pytest --flake8 --cov autoslot tests + pytest --cov autoslot tests - name: Extract branch name shell: bash run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" diff --git a/autoslot.py b/autoslot.py index c3cd935..fdcc8a4 100644 --- a/autoslot.py +++ b/autoslot.py @@ -31,7 +31,10 @@ def assignments_to_self(method) -> set: names = set() # a and b are a pair of bytecode instructions; b follows a. for a, b in zip(i0, i1): - accessing_self = (a.argval == instance_var and a.opname == 'LOAD_FAST') + accessing_self = ( + a.argval == instance_var + and a.opname in ('LOAD_FAST', 'LOAD_DEREF') + ) storing_attribute = (b.opname == 'STORE_ATTR') if accessing_self and storing_attribute: names.add(b.argval) diff --git a/pyproject.toml b/pyproject.toml index 4ee1b0b..0ed7c43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,8 +11,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", diff --git a/requirements-test.txt b/requirements-test.txt index 92b49d7..358911d 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,3 @@ pytest>=4.0.0 pytest-cov coveralls -pytest-flake8 diff --git a/tests/test_slots.py b/tests/test_slots.py index 697a180..506fc58 100644 --- a/tests/test_slots.py +++ b/tests/test_slots.py @@ -47,6 +47,45 @@ def __init__(self, a, b): a.z = 3 +def test_slots_load_deref(): + """Values can come from either LOAD_FAST or LOAD_DEREF + opcodes, so we need to handle both.""" + class A(Slots): + def __init__(self, a, b): + self.x = a + + def f(): + """Simply by referring to self in another scope + is enough to change the `self` accessing opcodes + in __init__ to become LOAD_DEREF instead of + LOAD_FAST. We don't even have to call `f`.""" + print(self) + + self.y = b + + # Testing to see that the + # bytecode processor identifies things + # correctly. + self.x = 'bleh' + + assert '__module__' in A.__dict__ + assert '__init__' in A.__dict__ + assert '__slots__' in A.__dict__ + assert A.__dict__['__slots__'] == {'x', 'y'} + + a = A(1, 2) + assert hasattr(a, 'x') + assert hasattr(a, 'y') + # Just checking that we didn't pick up the wrong names + assert not hasattr(a, 'a') + assert not hasattr(a, 'b') + assert hasattr(a, '__slots__') + assert not hasattr(a, '__dict__') + # Can't assign new attributes + with pytest.raises(AttributeError): + a.z = 3 + + def test_slots_weakref(): """Basic usage of the Slots metaclass.""" class A(Slots):