PyCharm Plugin developement: multiResolveCalleeFunction does not resolve properly in test case

Planned
import jwt
decoded = jwt.decode(token, "PyCharmCommunity")

I am writing a PyCharm plugin where I am trying to get to the declaration of the invocation jwt.decode(token, "PyCharmCommunity") in the above snippet. The following snippet works fine if the plugin is run using Gradle runIDE task(implementing the appStarter extension point).

TypeEvalContext typeEvalContext = TypeEvalContext.codeCompletion(getProject(), psiFile);
PyResolveContext resolveContext = PyResolveContext.defaultContext(typeEvalContext);
List<PyCallable> resolveFunctions = callExpression.multiResolveCalleeFunction(resolveContext);

I configured Python SDK for the loaded project to get this snippet working. The SDK is pointed to essentially a python virtual environment where all the relevant packages are installed. The above snippet resolves to the actual declaration of jwt.decode in the virtual environment, which is something like,

venv/lib/python3.8/site-packages/jwt/api_jwt.py

Now, I was also trying to write test cases for this snippet. I've set up a test environment where CodeInsightTestFixture is used for setting up project and SDK and loading the python test file. However, in the test environment, when the above snippet is invoked, the resolvedFunction is not the same. It now resolves to a file like the following,

home/user/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/typeshed/stubs/jwt/jwt/__init__.pyi


Am I missing something here in the test environment that limits the functionality of the multiResolve API?

The plugin has been set up using gradle-intellij-plugin template and for Pycharm Community. The test environment uses Junit3 and the test cases extend com.intellij.testFramework.UsefulTestCase. The SDK path is same for both of the mentioned cases.

0
10 comments

please do not delete and repost threads, thanks

 

0

Extremely sorry for deleting the previous one. Saw that question got answered tagged but there was not any comment in the thread. As I'm new to the community, is there any obvious reason behind thread tags, which I should know?

0

hm strange, threads pending answer usually get "planned" tag like this one. no worries

0

thanks for clarifying

0

Are PyCharm versions same?

Are `sdk.getRootProvider().getFiles(OrderRootType.CLASSES)` same in both cases?

0

  About the version, as far as I understand, the versions should be the same. But is there a way to check this?
I am setting the PyCharm version in gradle.properties file. Is this approach sufficient for setting same PyCharm version for both test suite and plugin execution using runIde task?

  `sdk.getRootProvider().getFiles(OrderRootType.CLASSES)` are not same for both cases. Although the SDK is set using the same virtual environment path, for the test suite I got,

0 = {VirtualDirectoryImpl@12576} "file:///home/kknock/project/build/envs/myenv/bin"
1 = {VirtualDirectoryImpl@12577} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.pycharm/pycharmPC/2021.2/7c8fe1875ad1b9629b00ce255fcc468019846708/pycharmPC-2021.2/system/python_stubs/2055529837"
2 = {VirtualDirectoryImpl@12578} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/python-skeletons"
3 = {VirtualDirectoryImpl@12579} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/typeshed/stdlib"
4 = {VirtualDirectoryImpl@12580} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/typeshed/stubs/jwt"
5 = {VirtualDirectoryImpl@12581} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/typeshed/stubs/six"
6 = {VirtualDirectoryImpl@12582} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.idea/unzipped.com.jetbrains.plugins/PythonCore-212.4746.13/python-ce/helpers/typeshed/stubs.........................................
...........................................................
........................................................................................

Whereas, for runIde task I got,

0 = {VirtualDirectoryImpl@17014} "file:///home/kknock/project/build/bootstrap/python3.8.10/lib/python3.8"
1 = {VirtualDirectoryImpl@17015} "file:///home/kknock/project/build/bootstrap/python3.8.10/lib/python3.8/lib-dynload"
2 = {VirtualDirectoryImpl@17016} "file:///home/kknock/project/build/envs/myenv/lib/python3.8/site-packages"
3 = {VirtualDirectoryImpl@17017} "file:///home/kknock/project/build/idea-sandbox/system/python_stubs/2055529837"
4 = {VirtualDirectoryImpl@17018} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.pycharm/pycharmPC/2021.2/7c8fe1875ad1b9629b00ce255fcc468019846708/pycharmPC-2021.2/plugins/python-ce/helpers/python-skeletons"
5 = {VirtualDirectoryImpl@17019} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.pycharm/pycharmPC/2021.2/7c8fe1875ad1b9629b00ce255fcc468019846708/pycharmPC-2021.2/plugins/python-ce/helpers/typeshed/stdlib"
6 = {VirtualDirectoryImpl@17020} "file:///home/kknock/.gradle/caches/modules-2/files-2.1/com.jetbrains.intellij.pycharm/pycharmPC/2021.2/7c8fe1875ad1b9629b00ce255fcc468019846708/pycharmPC-2021.2/plugins/stubs.........................................
...................................................................................................................................................

0

How do you configure sdk?

0
python_sdk = SdkConfigurationUtil.createAndAddSDK(pathToSdk, PythonSdkType.getInstance());
SdkConfigurationUtil.setDirectoryProjectSdk(project, python_sdk);
0

Do you have sources attached? If gradle-intellij-plugin is fresh enough, they should have been attached automatically.

Could you please debug this place https://github.com/JetBrains/intellij-community/blob/master/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java#L448?

Paths should be the same, it is not clear yet why they are different.

0

Thanks a ton for the clue! Could fix the test behavior.
Let me describe my debugging results in short. Also, I have some follow-up questions.

private static List<VirtualFile> buildSdkPaths(@NotNull Sdk sdk,
@NotNull List<VirtualFile> sdkRoots,
@NotNull List<VirtualFile> userAddedRoots) {

While debugging the above snippet for test case, sdkRoots was,

file:///home/kknock/project/python-environment/setup-test-environment/build/pythons/py37/bin

In contrast, for plugin run using runIde, sdkRoots was,

"file:///home/kknock/project/python-environment/setup-test-environment/build/pythons/py37/lib/python3.7"
"file:///home/kknock/project/python-environment/setup-test-environment/build/pythons/py37/lib/python3.7/lib-dynload"
"file:///home/kknock/project/python-environment/setup-test-environment/build/pythons/py37/lib/python3.7/site-packages"

Now the callsite of updateSdkPaths method is as follows,

updateSdkPaths(sdk, evaluateSysPath(sdk), project);

Here, the evaluateSysPath method, in turn, invokes PythonSdkType.getSysPath(sdk), which treats unit tests(if ApplicationEx is not in stress test) differently with a MOCK_SYS_PATH_KEY. (https://github.com/JetBrains/intellij-community/blob/master/python/src/com/jetbrains/python/sdk/PythonSdkType.java#L441)

So all I did is: in the TestCase setUp, invoked ApplicationManagerEx.setInStressTest(true). The paths are the same now for both cases, and multiResolveCalleeFunction is also working as expected.

Although this small trick serves my purpose well, I could not find much detail about the Stress mode. Is there any available documentation on this? And is there anything that should be kept in mind while using this mode in the test setup?

Thanks again for the help!

0

Please sign in to leave a comment.