Skip to content

Conversation

@julianstirling
Copy link
Contributor

@julianstirling julianstirling commented Nov 4, 2025

Adds a mock_all_slots option to create_thing_without_server. This will follow the default specified by thing_slot, so if the default is None no mock is created.

If it is a mapping with no default I think one instance is created, this needs checking in a test is tested.

  • This needs unit tests before merging.

I have targeted it at #195 so the diff is clear.

Closes #198

@rwb27
Copy link
Collaborator

rwb27 commented Nov 4, 2025

Great :) Glad this works, and it seems like it wasn't too much code to implement it.

I am thinking that it is probably a sensible idea to create a submodule called testing and move this there - along with probably a few other helpful things (like the not-yet-implemented MockServer). Hopefully that makes it easier to find and import.

@barecheck
Copy link

barecheck bot commented Nov 4, 2025

Barecheck - Code coverage report

Total: 94.52%

Your code coverage diff: 0.13% ▴

✅ All code changes are covered

@julianstirling
Copy link
Contributor Author

I understand thing_slots a lot better after implementing this so that is a nice side effect. It is tested.

I think moving it to a testing module is probably a good idea. I like the idea of:

from labthings-fastapi.testing import create_thing_without_server

I think it makes it very clear that this not intended for actual use.

@julianstirling julianstirling marked this pull request as ready for review November 4, 2025 18:33
Copy link
Collaborator

@rwb27 rwb27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. I've made a couple of suggestions that might be nice, but don't change the way it works meaningfully.

It would be good to move this to a testing module as we discussed, I'm happy for you to do that now, or we can do it later.

Comment on lines +308 to +310
# Note that this causes mypy to throw an `attr-defined` error as _mock
# only exists in the MockThingServerInterface
thing._thing_server_interface._mocks.append(mock) # type: ignore[attr-defined]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I've done in situations like this is use type narrowing:

Suggested change
# Note that this causes mypy to throw an `attr-defined` error as _mock
# only exists in the MockThingServerInterface
thing._thing_server_interface._mocks.append(mock) # type: ignore[attr-defined]
interface = thing._thing_server_interface
if isinstance(interface, MockThingServerInterface):
interface._mocks.append(mock)
else:
raise TypeError("Slots may not be mocked when a Thing is attached to a real server."

It's a bit more verbose, but it's probably a helpful check to have, as well as eliminating a type ignore.

# only exists in the MockThingServerInterface
thing._thing_server_interface._mocks.append(mock) # type: ignore[attr-defined]

attr.connect(thing, mocks, ...)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might it make sense to do this in a separate loop? Your code above does an impressively thorough job of constructing a collection of mock Things that you can pass to attr.connect without having to mess with the ThingSlot code (which I really like). However, the first slot will not see mocked Things that are added to satisfy later slots.

Splitting the loop means all the slots see all the mocked Things, which makes it function just a little bit more like the real thing, and might catch odd edge cases where there are interactions between multiple slots. I realise that is very edge-casey, but it's a pretty minor tweak so why not...

Suggested change
attr.connect(thing, mocks, ...)
for attr_name, attr in class_attributes(thing):
if isinstance(attr, ThingSlot):
attr.connect(thing, mocks, ...)

@rwb27
Copy link
Collaborator

rwb27 commented Nov 10, 2025

Thinking about review order, I think it might make sense to merge #194/#195 without too many more changes, then we can add the testing module and this code in a (very near) future PR.

@julianstirling
Copy link
Contributor Author

Yeah this is only targeted to #195 so it has a sensible diff. I think aiming it at main once those are merged makes sense

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