-
Notifications
You must be signed in to change notification settings - Fork 3
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
Feeds #16
Conversation
There's an open issue on mypy for when there are circular imports AND re-exporting a name. This appears to be what we're seeing here. python/mypy#4049
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly fine; I think we need to work out how (and test) we're going to handle failures getting data from feeds.
|
||
|
||
def test_multiple_feeds_same_name_invalid(): | ||
with assert_config_error(f"Feeds must have unique names at state_machines.example.feeds"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This string doesn't have any format placeholders in -- consider dropping the f
prefix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if len(set(x.name for x in feeds)) < len(feeds): | ||
raise ConfigError( | ||
f"Feeds must have unique names at {'.'.join(path + ['feeds'])}", | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For even nicer errors, we could use a collections.Counter
to detect exactly which feeds had non-unique names. (I'm not sure how many feeds we're expecting to exist in each config file).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect it will be typically 1, sometimes 1<n<5. I don't think this is necessary for now.
from routemaster.exit_conditions import Context, ExitConditionProgram | ||
from routemaster.exit_conditions import ExitConditionProgram | ||
|
||
if False: # typing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the rationale behind this being a fake import -- is it circular?
I'm ok with using the if False
idiom if there are conflicts on the import or it's a major performance hit, but would rather just import things directly for simpler cases as it's a bit ugly (and also makes the type annotations a bit ugly too).
(future occurrences not commented)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the rationale behind this being a fake import -- is it circular?
Yes
This is only to support typing, and in Python 3.7 we can switch to 'if TYPING'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, could we have a comment about these being circular? (possibly as well as the need for it only being for typing).
|
||
def __init__( | ||
self, | ||
label: str, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Elsewhere (in the API at least) we call this a label_name
(with label
meaning a fully qualified name plus state machine), should we use that terminology here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I'm not sure about this. A label should be just the string, I think we should probably change the Label
in state_machine
to something like LabelRef
. Won't do this in this PR though.
@@ -45,15 +45,15 @@ jobs: | |||
# Run tox, caching the .tox directory | |||
- restore_cache: | |||
name: Restore .tox cache | |||
key: deps-tox-{{ .Branch }}-{{ checksum "scripts/linting/requirements.txt" }}-{{ checksum "scripts/testing/requirements.txt" }}-{{ checksum "setup.py" }} | |||
key: deps-tox-{{ .Branch }}-{{ checksum "scripts/linting/requirements.txt" }}-{{ checksum "scripts/typechecking/requirements.txt" }}-{{ checksum "scripts/testing/requirements.txt" }}-{{ checksum "setup.py" }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 to adding a typechecking requirements.txt; this change (and the similar one below) should probably be cherry-picked to master though.
from routemaster.utils import get_path | ||
|
||
|
||
def feeds_for_state_machine(state_machine) -> Dict[str, 'Feed']: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: should the argument by type-annotated? (I'm not sure how much typing coverage we're aiming for)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually can't here due to python/mypy#4049 – there's detail in the commit message that removed the type.
routemaster/feeds.py
Outdated
self.data = None | ||
self.state_machine = state_machine | ||
|
||
def fetch(self, label: str): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: given that this is lazy and without return value, perhaps it should be named preload
or ensure_fetched
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
606b673 - prefetch
self.state_machine, | ||
) | ||
|
||
response = requests.get(url) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What behaviour do we want if this errors? (Should this raise_for_status
?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, this should fail for now. We might want to allow for more in the future, maybe 404 should be allowed for example. 473539d
|
||
|
||
@httpretty.activate | ||
def test_fetch_only_once(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test is a duplicate of test_only_loads_feed_once
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ish. This tests it directly on the feed, the other through a context. Given it's the context's responsibility to pre-warm I think it's worth having this test on both.
|
||
|
||
@httpretty.activate | ||
def test_lookup(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test is a duplicate of test_accesses_variable_in_feed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite, test_accesses_variable_in_feed
goes through a layer of dynamic dispatch (in a way) in the context, which is worth testing I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great if we could have explicit comments about the typing imports which are circular, fine otherwise.
Do you think this is necessary? I thought the |
Merging now, will address if needed on master. |
I've seen some projects put all their typing-only imports under this sort of guard, which I'm not sure I see the point of. Given that we only use it for that reason here we maybe don't, but I was then surprised to see that you'd commented them as If we're aiming to generally put typing imports unguarded (which is the style I've used elsewhere and would encourage; from what I've seen it's what we're doing here anyway), then the cases where we're not doing that are interesting for the reason we're not doing that rather than for the fact that they're typing imports. Thus a comment about them being circular is most useful. I'm open to having a comment which says something like "circular typing-only imports" if you feel we need to call out that they're typing imports. |
https://app.asana.com/0/465891412411656/496393890703246