-
Notifications
You must be signed in to change notification settings - Fork 6
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
Add cache integration support #16
Conversation
Ping for review @vodik @moises-silva @dkerr |
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 you might want to tighten your line parsing, but otherwise looks reasonable.
|
||
def get_cache_dict(self, path=None): | ||
if path is None: | ||
path = '/'.join(['pytest-interactive', 'cache']) |
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.
Where does this actually end up on the filesystem?
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.
<pytest run dir>/.cache/v/pytest-interactive/cache
pytest
stores lastfailed
@ <pytest run dir>/.cache/v/lastfailed
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.
Nice, glad they're following xdg
# update the local shell's ns | ||
if testset: | ||
self.shell.user_ns[cache_key] = testset | ||
return |
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 happens if someone inputs 'cache foo as '
?
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.
See below.
self.shell.user_ns.pop(cache_key) | ||
self.tr.write( | ||
"Deleted cache entry for '{}'\n".format(cache_key)) | ||
return |
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.
Or something like 'cache del as '
actually?
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.
hehe bad stuff.
So good point we need to validate names.
Any suggestion on how to do that?
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.
Tokenize the string first, consume the tokens one by one.
tokens = line.split() # or use an alternative that respects quoting if you're feeling fancy
assert tokens[0] == 'cache'
if tokens[1] == 'del':
assert len(tokens) == 3 # cache del foo
name = tokens[2]
# ...
else:
assert len(tokens) == 4 # cache foo as ...
assert token[2] == 'as'
name = tokens[1]
# ...
Which will also more correctly handle the case of putting too many whitespaces. Since you don't strip after you partition, i wonder how the following inputs would be handled:
cache foo as bar
<- two spaces between foo and as, github is just cleaning it up for me☹️ cache some random string as there's more to come
cache as as as
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.
Thanks for the feedback. Yes more stringent parsing is needed.
This seems like a good spot to bring in hypothesis when I finally get to #8...
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 would also suggest requiring cache add
and cache del
, so you can correctly deal with a cache called del: cache del del...
and cache add del...
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.
@vodik so have add
along side blah as foo
?
I have to say I like the as
/del
as ptk gives you highlighting (yes i know it's hacky).
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.
Take a step back and spec out how you want to parse the command:
operation = "add" | "del"
identifier = [A-Za-z0-9]
cmd = "cache" operation identifier ["as" identifier]
something like that, and unambigious. I'm not sure if you require "as", but if you don't, for example, what is the actual error here: 'cache del as'
? Incorrect name? or missing identifier next to the as?
Oh and obviously I should write some docs... |
@vodik fixed this up to simply use the Let me know if there's anything I missed ;) |
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.
Better, but could still use some work.
"Deleted cache entry for '{}'\n".format(name)) | ||
return | ||
|
||
elif first == 'add': |
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 doesn't match your documentation:
'0' selected >>> cache tt.test_setB.test_modes setb
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.
hah! thanks.
self.shell.user_ns[target] = testset | ||
return | ||
|
||
self.tt.err("{} is invalid".format(line)) |
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.
Probably not a bad idea to print either/both a usage line or a more specific error, if you can.
|
||
if first == 'del': | ||
# delete an entry | ||
name = tokens[1] |
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.
So no error if length is greater than 3?
8111986
to
659f6ab
Compare
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.
Okay, while I think you should spend a bit more effort on tightening up the error messages, this looks functional.
@vodik what more would you like with error msgs? |
Looks good to me. Actually, one last thing... |
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.
Yeah, looks fine to me now. Just two small comments, but I guess its a bit of scope creep - I could see the identifier validity problem as something more general
"Created cache entry for '{}'\n".format(name)) | ||
return | ||
|
||
self.tt.err("{} is invalid. See %cache? for usage.".format(line)) |
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.
Heh, for all the hard times I give you for putting unnecessary quotes around your format strings, here's actually a good place to put some in.
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.
lolz
# create a new entry | ||
name, target = tokens[1:] | ||
testset = self.ns_eval(name) | ||
self.tt.set_cache_items(target, testset) |
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.
Oh, would you maybe want to validate that target
is a valid python keyword? You know, starts with a letter and doesn't contain invalid characters like dashes?
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 good call.
This adds support for stashing `TestSet`s in the pytest cache between runs. By default the `lastfailed` set is always inserted into the shell namespace even when the user didn't pass `--lf`. You can use: - cache # print a summary - cache add <name> <cache key> # create an entry - cache del <name> # delete and entry Resolves #15
@vodik good enough? |
This adds support for stashing
TestSet
s in the pytest cache betweenruns. By default the
lastfailed
set is always inserted into theshell namespace even when the user didn't pass
--lf
.You can use:
cache <name> as <cache key> # create an entry
cache del <cache key> # delete and entry
cache # print a summary
Resolves #15