Skip to content

digitalio: Improve DigitalInOut constructor, add finaliser #9795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

jepler
Copy link

@jepler jepler commented Nov 7, 2024

Now it's possible to construct outputs or enable pulls immediately:

>>> d = digitalio.DigitalInOut(board.A0, pull=digitalio.Pull.UP)
>>> d.pull
digitalio.Pull.UP
>>> d = digitalio.DigitalInOut(board.A0, value=True)
>>> d.direction
digitalio.Direction.OUTPUT
>>> d.value
True
>>> d = digitalio.DigitalInOut(board.A0, value=False, drive_mode=digitalio.DriveMode.OPEN_DRAIN)
>>> d.drive_mode
digitalio.DriveMode.OPEN_DRAIN

The finaliser means that if a pin object is allowed to go out of scope, then it will be deinitialized automatically when GC runs. this is a potential incompatibility: some hypothetical code that intentionally leaked a pin might function differently, i.e.

digitalio.DigitalInOut(board.A0).switch_to_output(True)

as a way to stick a pin in output mode indefinitely will no longer work (but may still appear to work "for awhile" because gc doesn't run right away).

I made this change in part because it simplifies error handling in the constructor: An incorrect argument would otherwise have left the pin stuck in allocated state until the interpreter was reset; with this change, it's available again though not until the GC runs so it would remain perplexing in interactive situations:

>>> d = digitalio.DigitalInOut(board.A0, pull=7)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pull must be of type Pull or None, not int
>>> d = digitalio.DigitalInOut(board.A0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: A0 in use
>>> gc.collect()
>>> d = digitalio.DigitalInOut(board.A0)
>>> d
<DigitalInOut>

Now it's possible to construct outputs or enable pulls immediately:

```py
>>> d = digitalio.DigitalInOut(board.A0, pull=digitalio.Pull.UP)
>>> d.pull
digitalio.Pull.UP
```

```py
>>> d = digitalio.DigitalInOut(board.A0, value=True)
>>> d.direction
digitalio.Direction.OUTPUT
>>> d.value
True
```

```py
>>> d = digitalio.DigitalInOut(board.A0, value=False, drive_mode=digitalio.DriveMode.OPEN_DRAIN)
>>> d.drive_mode
digitalio.DriveMode.OPEN_DRAIN
```

The finaliser means that if a pin object is allowed to go out of scope,
then it will be deinitialized automatically when GC runs. **this is a
potential incompatibility**: some hypothetical code that intentionally
leaked a pin might function differently, i.e.
```py
digitalio.DigitalInOut(board.A0).switch_to_output(True)
```
as a way to stick a pin in output mode indefinitely will no longer work
(but may still appear to work "for awhile" because gc doesn't run right
away).

I made this change in part because it simplifies error handling in the
constructor: An incorrect argument would otherwise have left the pin
stuck in allocated state until the interpreter was reset; with this
change, it's available again though not until the GC runs so it would
remain perplexing in interactive situations:
```py
>>> d = digitalio.DigitalInOut(board.A0, pull=7)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pull must be of type Pull or None, not int
>>> d = digitalio.DigitalInOut(board.A0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: A0 in use
>>> gc.collect()
>>> d = digitalio.DigitalInOut(board.A0)
>>> d
<DigitalInOut>
```
@jepler
Copy link
Author

jepler commented Nov 7, 2024

On reflection I think that the constructor error handling needs to ensure the object's immediately deallocated. but I'll let this run and get some important info: does this fit, or does it add enough code to overflow our most constrained builds...?

@dhalbert
Copy link
Collaborator

dhalbert commented Nov 7, 2024

I have been wanting this for years :) . I hope it fits.

@dhalbert
Copy link
Collaborator

dhalbert commented Nov 7, 2024

But @tannewt has not been in favor of some of this: see #5124 and #8534.

@jepler
Copy link
Author

jepler commented Nov 8, 2024

And it doesn't fit, either

@jepler jepler closed this Nov 8, 2024
@relic-se
Copy link

relic-se commented Nov 8, 2024

From @tannewt 's comments on #8534 :

Having direction in the constructor would require cross parameter validation (if pull is set but direction is output then fail.)

Is there a specific reason why cross parameter validation would be something to avoid within DigitalInOut or other classes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants