-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PR: Fix introspection testing (CI) #22053
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
Conversation
@dalthviz Can you please give a bit of explanation about this PR so that I can review it? What went wrong and how does this fix it? |
Sure @jitseniesen ! So basically here I:
Related to how these changes fix things, my guess is that the initial migration of the Editor caused the previous logic in place for handling the introspection for the tests (via an env var) to not be enough. This due to the Editor initialization logic now taking place alongside the other plugins which, regardless of the env var, makes the Editor interact with the completion plugin. I would say the main problem is that the env var approach doesn't deal with the providers still appearing from the config side of things as enabled 🤔 My local testing suggested that the changes here prevent seeing the |
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 tested it locally and it does get rid of the QThread error. It is also much neater without the environment variable.
I have one substantive (and rather long, sorry!) comment on the can_close function, mostly about the existing code which you probably did not write. Let me know what you think.
I also made two comments (about CONF and running_under_pytest) about points that are probably fine, so just saying it's fine is enough to satisfy me.
if use_introspection: | ||
os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True' | ||
CONF.set('completions', ('enabled_providers', 'lsp'), True) | ||
CONF.set('completions', ('enabled_providers', 'fallback'), True) | ||
CONF.set('completions', ('enabled_providers', 'snippets'), True) | ||
else: | ||
try: | ||
os.environ.pop('SPY_TEST_USE_INTROSPECTION') | ||
except KeyError: | ||
pass | ||
CONF.set('completions', ('enabled_providers', 'lsp'), False) | ||
CONF.set('completions', ('enabled_providers', 'fallback'), False) | ||
CONF.set('completions', ('enabled_providers', 'snippets'), False) |
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.
Just checking ... it is not necessary to undo these changes in the CONF after the test, is it?
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 don't think so but to be sure checked and seems like the logic that enables not worrying about possible effects to the config after running a test is at:
Lines 219 to 224 in 071e646
def get_conf_path(filename=None): | |
"""Return absolute path to the config file with the specified filename.""" | |
# Define conf_dir | |
if running_under_pytest() or get_safe_mode(): | |
# Use clean config dir if running tests or the user requests it. | |
conf_dir = get_clean_conf_dir() |
So when running tests, a clean dir is used for the config 👍
if ( | ||
running_under_pytest() | ||
and os.environ.get('SPY_TEST_USE_INTROSPECTION') | ||
): | ||
self.update_lsp_configuration(python_only=True) | ||
self.update_lsp_configuration(python_only=True) | ||
|
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.
Why did you remove the running_under_pytest()
condition?
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, I overlooked the comment 😅 Will readd the running_under_pytest()
validation and the comment 👍
spyder/plugins/completion/plugin.py
Outdated
else: | ||
can_close |= True |
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 is just a complicated way to write can_close = True
(assuming that can_close
is always a bool).
Actually, I don't understand the logic of the whole can_close
function, regardless of your change. It seems to me that the function should return False
if there is at least one provider that is running for which provider.can_close()
returns False
. This is also what the docstring indicates. So if there are two running providers, one of which can close and the other can not, then the function should return False
. However, I believe that's not what the code does. In fact, it returns True
if there is at least one provider for which provider.can_close()
returns True
. So in the case that there are two running providers, one of which can close and the other can not, then the function actually return True
.
Additionally, I don't like the use of the bitwise |
operator instead of the logical or
operator.
For clarity, this is how I would write the function (but I'm not sure that is the intended meaning):
def can_close(self) -> bool:
"""Check if any provider has any pending task."""
can_close = True
for provider_name in self.providers:
provider_info = self.providers[provider_name]
if provider_info['status'] == self.RUNNING:
provider = provider_info['instance']
provider_can_close = provider.can_close()
can_close = can_close and provider_can_close
return can_close
Or maybe:
def can_close(self) -> bool:
"""Check if any provider has any pending task."""
for provider_name in self.providers:
provider_info = self.providers[provider_name]
if provider_info['status'] == self.RUNNING:
provider = provider_info['instance']
if not provider.can_close():
return False
return True
What do you say, does this make sense?
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.
You are totally right! So indeed this logic should be preventing the plugin close if any of the running providers is unable to be closed. Also, I think this logic is following a pattern like the one used over the plugins registry to check if things can be close/deleted:
spyder/spyder/api/plugin_registration/registry.py
Lines 573 to 599 in 071e646
def can_delete_all_plugins(self, | |
excluding: Optional[Set[str]] = None) -> bool: | |
""" | |
Determine if all plugins can be deleted except the ones to exclude. | |
Parameters | |
---------- | |
excluding: Optional[Set[str]] | |
A set that lists plugins (by name) that will not be deleted. | |
Returns | |
------- | |
bool | |
True if all plugins can be closed. False otherwise. | |
""" | |
excluding = excluding or set({}) | |
can_close = True | |
# Check external plugins | |
for plugin_name in ( | |
set(self.external_plugins) | set(self.internal_plugins)): | |
if plugin_name not in excluding: | |
can_close &= self.can_delete_plugin(plugin_name) | |
if not can_close: | |
break | |
return can_close |
So my guess is that the original idea of the check was to do something like your first suggestion but using &=
So something like:
def can_close(self) -> bool:
"""Check if any provider has any pending task."""
can_close = True
for provider_name in self.providers:
provider_info = self.providers[provider_name]
if provider_info['status'] == self.RUNNING:
provider = provider_info['instance']
can_close &= provider.can_close()
return can_close
We could even do:
def can_close(self) -> bool:
"""Check if any provider has any pending task."""
can_close = True
for provider_name in self.providers:
provider_info = self.providers[provider_name]
if provider_info['status'] == self.RUNNING:
provider = provider_info['instance']
can_close &= provider.can_close()
if not can_close:
break
return can_close
Maybe your second suggestion (with the early return
) is better? 🤔 What do you think @ccordoba12 ?
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.
Maybe your second suggestion (with the early return) is better? 🤔 What do you think @ccordoba12 ?
I like that suggestion. I think it's simpler and easier to follow.
spyder/plugins/completion/plugin.py
Outdated
else: | ||
can_close |= True |
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.
Same remark as for the function can_close()
above.
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 the same applies for this, so indeed, the method should return True
only if all the providers can be closed and return False
otherwise 👍
Prevent closing if is not possible to shutdown a provider
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.
One small question for you @dalthviz, the rest looks good to me.
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.
Looks good to me, thanks @dalthviz!
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.
All fine now, thanks Daniel!
Description of Changes
Properly handle instrospection usage via the Completions plugin configuration
Issue(s) Resolved
Fixes #22012
Affirmation
By submitting this Pull Request or typing my (user)name below,
I affirm the Developer Certificate of Origin
with respect to all commits and content included in this PR,
and understand I am releasing the same under Spyder's MIT (Expat) license.
I certify the above statement is true and correct: dalthviz