diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml
index fd61de48cc49..a4419c65a061 100644
--- a/python/src/META-INF/python-core-common.xml
+++ b/python/src/META-INF/python-core-common.xml
@@ -785,6 +785,7 @@
+
diff --git a/python/src/com/jetbrains/numpy/codeInsight/SciPyDocumentationLinkProvider.kt b/python/src/com/jetbrains/numpy/codeInsight/SciPyDocumentationLinkProvider.kt
new file mode 100644
index 000000000000..efe1f22759eb
--- /dev/null
+++ b/python/src/com/jetbrains/numpy/codeInsight/SciPyDocumentationLinkProvider.kt
@@ -0,0 +1,53 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.jetbrains.numpy.codeInsight
+
+import com.google.common.collect.ImmutableMap
+import com.intellij.psi.PsiElement
+import com.jetbrains.python.documentation.PythonDocumentationLinkProvider
+import com.jetbrains.python.documentation.PythonDocumentationProvider
+import java.io.BufferedReader
+import java.io.IOException
+import java.io.InputStreamReader
+
+
+class SciPyDocumentationLinkProvider : PythonDocumentationLinkProvider {
+
+ private val nameToWebpageName: Map by lazy {
+ val b = ImmutableMap.builder()
+ try {
+ BufferedReader(
+ InputStreamReader(
+ SciPyDocumentationLinkProvider::class.java
+ .getResourceAsStream("/com/jetbrains/numpy/codeInsight/scipyNameMapping.tsv"), // generated by scipy_doc_mapping.py
+ Charsets.UTF_8
+ )
+ ).use { inputStream ->
+ inputStream.lines().forEach { line ->
+ val kv = line.split("\t".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ b.put(kv[0], kv[1])
+ }
+ }
+ }
+ catch (e: IOException) {
+ throw RuntimeException(e)
+ }
+
+ b.build()
+ }
+
+ override fun getExternalDocumentationUrl(element: PsiElement?, originalElement: PsiElement?): String? {
+ val qname = PythonDocumentationProvider.getFullQualifiedName(element)
+
+ return if (qname != null && qname.firstComponent in listOf("numpy", "scipy")) {
+ val webPage = nameToWebpageName.get(qname.toString())
+ if (webPage != null) {
+ "https://docs.scipy.org/doc/${qname.firstComponent}/reference/generated/$webPage.html"
+ } else {
+ "https://docs.scipy.org/doc/${qname.firstComponent}/reference/"
+ }
+ }
+ else null
+
+ }
+
+}
\ No newline at end of file
diff --git a/python/src/com/jetbrains/python/documentation/scipyNameMapping.tsv b/python/src/com/jetbrains/numpy/codeInsight/scipyNameMapping.tsv
similarity index 100%
rename from python/src/com/jetbrains/python/documentation/scipyNameMapping.tsv
rename to python/src/com/jetbrains/numpy/codeInsight/scipyNameMapping.tsv
diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java
index a658035761f9..9ab22848cb6b 100644
--- a/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java
+++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationMap.java
@@ -2,7 +2,7 @@
package com.jetbrains.python.documentation;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
@@ -17,17 +17,11 @@ import com.jetbrains.python.psi.PyFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* @author yole
@@ -46,28 +40,6 @@ public class PythonDocumentationMap implements PersistentStateComponent nameToWebpageName = ((Supplier