mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -349,7 +349,7 @@ private layoutWin(Map args, String target) {
|
||||
}
|
||||
|
||||
dir("skeletons") {
|
||||
fileset(dir: "$home/python/skeletons") {
|
||||
fileset(dir: "$pythonCommunityHome/skeletons") {
|
||||
include(name: "skeletons-win*.zip")
|
||||
}
|
||||
}
|
||||
@@ -390,7 +390,7 @@ private layoutMac(Map _args, String target) {
|
||||
}
|
||||
|
||||
dir("skeletons") {
|
||||
fileset(dir: "$home/python/skeletons") {
|
||||
fileset(dir: "$pythonCommunityHome/skeletons") {
|
||||
include(name: "skeletons-mac*.zip")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ but seemingly no one uses them in C extensions yet anyway.
|
||||
# * re.search-bound, ~30% time, in likes of builtins and _gtk with complex docstrings.
|
||||
# None of this can seemingly be easily helped. Maybe there's a simpler and faster parser library?
|
||||
|
||||
VERSION = "1.127" # Must be a number-dot-number string, updated with each change that affects generated skeletons
|
||||
VERSION = "1.128" # Must be a number-dot-number string, updated with each change that affects generated skeletons
|
||||
# Note: DON'T FORGET TO UPDATE!
|
||||
|
||||
import sys
|
||||
@@ -736,8 +736,29 @@ class ModuleRedeclarator(object):
|
||||
self._defined = {} # stores True for every name defined so far, to break circular refs in values
|
||||
self.doing_builtins = doing_builtins
|
||||
self.ret_type_cache = {}
|
||||
self.used_imports = emptylistdict() # qual_mod_name -> [imported_names,..]: actullay used imported names
|
||||
self.used_imports = emptylistdict() # qual_mod_name -> [imported_names,..]: actually used imported names
|
||||
|
||||
def initializeQApp(self):
|
||||
try: # QtGui should be imported _before_ QtCore package.
|
||||
# This is done for the QWidget references from QtCore (such as QSignalMapper). Known bug in PyQt 4.7+
|
||||
# Causes "TypeError: C++ type 'QWidget*' is not supported as a native Qt signal type"
|
||||
import PyQt4.QtGui
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# manually instantiate and keep reference to singleton QCoreApplication (we don't want it to be deleted during the introspection)
|
||||
# use QCoreApplication instead of QApplication to avoid blinking app in Dock on Mac OS
|
||||
try:
|
||||
from PyQt4.QtCore import QCoreApplication
|
||||
self.app = QCoreApplication([])
|
||||
return
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
self.app = QCoreApplication([])
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def indent(self, level):
|
||||
"Return indentation whitespace for given level."
|
||||
@@ -809,6 +830,7 @@ class ModuleRedeclarator(object):
|
||||
REPLACE_MODULE_VALUES = {
|
||||
("numpy.core.multiarray", "typeinfo"): "{}",
|
||||
("psycopg2._psycopg", "string_types"): "{}", # badly mangled __eq__ breaks fmtValue
|
||||
("PyQt5.QtWidgets", "qApp") : "QApplication()", # instead of None
|
||||
}
|
||||
if version[0] <= 2:
|
||||
REPLACE_MODULE_VALUES[(BUILTIN_MOD_NAME, "None")] = "object()"
|
||||
@@ -988,7 +1010,7 @@ class ModuleRedeclarator(object):
|
||||
# known properties of modules
|
||||
# {{"module": {"class", "property" : ("letters", ("getter", "type"))}},
|
||||
# where letters is any set of r,w,d (read, write, del) and "getter" is a source of typed getter.
|
||||
# if vlue is None, the property should be omitted.
|
||||
# if value is None, the property should be omitted.
|
||||
# read-only properties that return an object are not listed.
|
||||
G_OBJECT = ("lambda self: object()", None)
|
||||
G_TYPE = ("lambda self: type(object)", "type")
|
||||
@@ -1979,6 +2001,10 @@ class ModuleRedeclarator(object):
|
||||
@param p_name name of module
|
||||
"""
|
||||
action("redoing header of module %r %r", p_name, str(self.module))
|
||||
|
||||
if "pyqt" in p_name.lower(): # qt specific patch
|
||||
self.initializeQApp()
|
||||
|
||||
self.redoSimpleHeader(p_name)
|
||||
|
||||
# find whatever other self.imported_modules the module knows; effectively these are imports
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
Python Skeletons
|
||||
================
|
||||
|
||||
_This proposal is a draft._
|
||||
|
||||
Python skeletons are Python files that contain API definitions of existing
|
||||
libraries extended for static analysis tools.
|
||||
|
||||
Rationale
|
||||
---------
|
||||
|
||||
Python is a dynamic language less suitable for static code analysis than static
|
||||
languages like C or Java. Although Python static analysis tools can extract
|
||||
some information from Python source code without executing it, this information
|
||||
is often very shallow and incomplete.
|
||||
|
||||
Dynamic features of Python are very useful for user code. But using these
|
||||
features in APIs of third-party libraries and the standard library is not
|
||||
always a good idea. Tools (and users, in fact) need clear definitions of APIs.
|
||||
Often library API definitions are quite static and easy to grasp (defined
|
||||
using `class`, `def`), but types of function parameters and return values
|
||||
usually are not specified. Sometimes API definitions involve metaprogramming.
|
||||
|
||||
As there is not enough information in API definition code of libraries,
|
||||
developers of static analysis tools collect extended API data themselves and
|
||||
store it in their own formats. For example, PyLint uses imperative AST
|
||||
transformations of API modules in order to extend them with hard-coded data.
|
||||
PyCharm extends APIs via its proprietary database of declarative type
|
||||
annotations. The absence of a common extended API information format makes it
|
||||
hard for developers and users of tools to collect and share data.
|
||||
|
||||
|
||||
Proposal
|
||||
--------
|
||||
|
||||
The proposal is to create a common database of extended API definitions as a
|
||||
collection of Python files called skeletons. Static analysis tools already
|
||||
understand Python code, so it should be easy to start extracting API
|
||||
definitions from these Python skeleton files. Regular function and class
|
||||
definitions can be extended with additional docstrings and decorators, e.g. for
|
||||
providing types of function parameters and return values. Static analysis tools
|
||||
may use a subset of information contained in skeleton files needed for their
|
||||
operation. Using Python files instead of a custom API definition format will
|
||||
also make it easier for users to populate the skeletons database.
|
||||
|
||||
Declarative Python API definitions for static analysis tools cannot cover all
|
||||
dynamic tricks used in real APIs of libraries: some of them still require
|
||||
library-specific code analysis. Nevertheless the skeletons database is enough
|
||||
for many libraries.
|
||||
|
||||
The proposed [python-skeletons](https://github.com/JetBrains/python-skeletons)
|
||||
repository is hosted on GitHub.
|
||||
|
||||
|
||||
Conventions
|
||||
-----------
|
||||
|
||||
Skeletons should respect PEP-8 and PEP-257 style guides.
|
||||
|
||||
The most simple way of specifying types in skeletons is Sphinx docstrings.
|
||||
Function annotations could be used for specifying types, but they are
|
||||
available only for Python 3.
|
||||
|
||||
There is no standard notation for specifying types in Python code. We propose
|
||||
the following notation:
|
||||
|
||||
Foo # Class Foo visible in the current scope
|
||||
x.y.Bar # Class Bar from x.y module
|
||||
Foo | Bar # Foo or Bar
|
||||
(Foo, Bar) # Tuple of Foo and Bar
|
||||
list[Foo] # List of Foo elements
|
||||
dict[Foo, Bar] # Dict from Foo to Bar
|
||||
T # Generic type (T-Z are reserved for generics)
|
||||
T <= Foo # Generic type with upper bound Foo
|
||||
Foo[T] # Foo parameterized with T
|
||||
(Foo, Bar) -> Baz # Function of Foo and Bar that returns Baz
|
||||
|
||||
The formal syntax is defined in `pytypes` library (work in progress).
|
||||
|
||||
There are several shortcuts available:
|
||||
|
||||
unknown # Unknown type
|
||||
None # type(None)
|
||||
string # Py2: str | unicode, Py3: str
|
||||
bytestring # Py2: str | unicode, Py3: bytes
|
||||
bytes # Py2: str, Py3: bytes
|
||||
unicode # Py2: unicode, Py3: str
|
||||
|
||||
The syntax is a subject to change. It is almost compatible to Python (except
|
||||
function types), but its semantics differs from Python (no `|`, no implicitly
|
||||
visible names, no generic types). So you cannot use these expressions in
|
||||
Python 3 function annotations. See also `python-righarrow`, `typeannotations`.
|
||||
|
||||
The recommended way of checking the version of Python is:
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (2, 7) and sys.version_info < (3,):
|
||||
def from_27_until_30():
|
||||
pass
|
||||
|
||||
|
||||
PyCharm
|
||||
-------
|
||||
|
||||
PyCharm 3 can extract the following information from the skeletons:
|
||||
|
||||
* Parameters of functions and methods
|
||||
* Return types and parameter types of functions and methods
|
||||
* Types of assignment targets
|
||||
* Extra module members
|
||||
* TODO
|
||||
|
||||
PyCharm 3 comes with a snapshot of the Python skeletons repository. You
|
||||
should not modify it, because it will be updated with the PyCharm
|
||||
installation. If you want to change the skeletons, clone the skeletons GitHub
|
||||
repository into your PyCharm config directory:
|
||||
|
||||
cd <PyCharm config>
|
||||
git clone https://github.com/JetBrains/python-skeletons.git
|
||||
|
||||
where `<PyCharm config>` is:
|
||||
|
||||
* Mac OS X: `~/Library/Preferences/PyCharmXX/config`
|
||||
* Linux: `~/.PyCharmXX/config`
|
||||
* Windows: `<User home>\.PyCharmXX\config`
|
||||
|
||||
Please send your PyCharm-related bug reports and feature requests to
|
||||
[PyCharm issue tracker](http://youtrack.jetbrains.com/issues/PY).
|
||||
|
||||
|
||||
Feedback
|
||||
--------
|
||||
|
||||
If you want to contribute, send your pull requests to the Python skeletons
|
||||
repository on GitHub. Please make sure, that you follow the conventions above.
|
||||
|
||||
Use [code-quality](http://mail.python.org/mailman/listinfo/code-quality)
|
||||
mailing list to discuss Python skeletons.
|
||||
@@ -0,0 +1,377 @@
|
||||
"""Skeletons for built-in symbols."""
|
||||
|
||||
import sys as __sys
|
||||
|
||||
|
||||
def abs(number):
|
||||
"""Return the absolute value of the argument.
|
||||
|
||||
:type number: T
|
||||
:rtype: T | unknown
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def all(iterable):
|
||||
"""Return True if bool(x) is True for all values x in the iterable.
|
||||
|
||||
:type iterable: collections.Iterable
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def any(iterable):
|
||||
"""Return True if bool(x) is True for any x in the iterable.
|
||||
|
||||
:type iterable: collections.Iterable
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def bin(number):
|
||||
"""Return the binary representation of an integer or long integer.
|
||||
|
||||
:type number: numbers.Number
|
||||
:rtype: bytes
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def callable(object):
|
||||
"""Return whether the object is callable (i.e., some kind of function).
|
||||
Note that classes are callable, as are instances with a __call__() method.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def chr(i):
|
||||
"""Return a string of one character with ordinal i; 0 <= i < 256.
|
||||
|
||||
:type i: int
|
||||
:rtype: string
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def cmp(x, y):
|
||||
"""Return negative if x<y, zero if x==y, positive if x>y.
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def dir(object=None):
|
||||
"""If called without an argument, return the names in the current scope.
|
||||
Else, return an alphabetized list of names comprising (some of) the attributes
|
||||
of the given object, and of attributes reachable from it.
|
||||
|
||||
:rtype: list[string]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def divmod(x, y):
|
||||
"""Return the tuple ((x-x%y)/y, x%y).
|
||||
|
||||
:type x: numbers.Number
|
||||
:type y: numbers.Number
|
||||
:rtype: (int | long | float | unknown, int | long | float | unknown)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def filter(function_or_none, sequence):
|
||||
"""Return those items of sequence for which function(item) is true. If
|
||||
function is None, return the items that are true. If sequence is a tuple
|
||||
or string, return the same type, else return a list.
|
||||
|
||||
:type function_or_none: collections.Callable | None
|
||||
:type sequence: T <= list | collections.Iterable | bytes | unicode
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def getattr(object, name, default=None):
|
||||
"""Get a named attribute from an object; getattr(x, 'y') is equivalent to
|
||||
x.y. When a default argument is given, it is returned when the attribute
|
||||
doesn't exist; without it, an exception is raised in that case.
|
||||
|
||||
:type name: string
|
||||
:rtype: object | unknown
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def globals():
|
||||
"""Return the dictionary containing the current scope's global variables.
|
||||
|
||||
:rtype: dict[string, unknown]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def hasattr(object, name):
|
||||
"""Return whether the object has an attribute with the given name.
|
||||
|
||||
:type name: string
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def hash(object):
|
||||
"""Return a hash value for the object.
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def hex(number):
|
||||
"""Return the hexadecimal representation of an integer or long integer.
|
||||
|
||||
:type number: numbers.Integral
|
||||
:rtype: string
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def id(object):
|
||||
"""Return the identity of an object.
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def isinstance(object, class_or_type_or_tuple):
|
||||
"""Return whether an object is an instance of a class or of a subclass
|
||||
thereof.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def issubclass(C, B):
|
||||
"""Return whether class C is a subclass (i.e., a derived class) of class B.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def iter(source, sentinel=None):
|
||||
"""Get an iterator from an object. In the first form, the argument must
|
||||
supply its own iterator, or be a sequence. In the second form, the callable
|
||||
is called until it returns the sentinel.
|
||||
|
||||
:type source: collections.Iterable[T]
|
||||
:rtype: collections.Iterator[T]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def len(object):
|
||||
"""Return the number of items of a sequence or mapping.
|
||||
|
||||
:type object: collections.Sized
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def locals():
|
||||
"""Update and return a dictionary containing the current scope's local
|
||||
variables.
|
||||
|
||||
:rtype: dict[string, unknown]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def map(function, sequence, *sequence_1):
|
||||
"""Return a list of the results of applying the function to the items of
|
||||
the argument sequence(s).
|
||||
|
||||
:type function: ((T) -> V) | None
|
||||
:type sequence: collections.Iterable[T]
|
||||
:rtype: list[V] | bytes | unicode
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def next(iterator, default=None):
|
||||
"""Return the next item from the iterator.
|
||||
|
||||
:type iterator: collections.Iterator[T]
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def oct(number):
|
||||
"""Return the octal representation of an integer or long integer.
|
||||
|
||||
:type number: numbers.Integral
|
||||
:rtype: string
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def open(name, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=None, opener=None):
|
||||
"""Open a file, returns a file object.
|
||||
|
||||
:type name: string
|
||||
:type mode: string
|
||||
:type buffering: int
|
||||
:type encoding: string | None
|
||||
:type errors: string | None
|
||||
:rtype: file
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def ord(c):
|
||||
"""Return the integer ordinal of a one-character string.
|
||||
|
||||
:type c: string
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def pow(x, y, z=None):
|
||||
"""With two arguments, equivalent to x**y. With three arguments,
|
||||
equivalent to (x**y) % z, but may be more efficient (e.g. for longs).
|
||||
|
||||
:type x: numbers.Number
|
||||
:type y: numbers.Number
|
||||
:type z: numbers.Number | None
|
||||
:rtype: int | long | float | complex
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
if __sys.version_info < (3,):
|
||||
def range(start, stop=None, step=None):
|
||||
"""Return a list containing an arithmetic progression of integers.
|
||||
|
||||
:type start: numbers.Integral
|
||||
:type stop: numbers.Integral | None
|
||||
:type step: numbers.Integral | None
|
||||
:rtype: list[int]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def reduce(function, sequence, initial=None):
|
||||
"""Apply a function of two arguments cumulatively to the items of a sequence,
|
||||
from left to right, so as to reduce the sequence to a single value.
|
||||
|
||||
:type function: collections.Callable
|
||||
:type sequence: collections.Iterable
|
||||
:type initial: T
|
||||
:rtype: T | unknown
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def repr(object):
|
||||
"""
|
||||
Return the canonical string representation of the object.
|
||||
|
||||
:rtype: string
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def round(number, ndigits=None):
|
||||
"""Round a number to a given precision in decimal digits (default 0 digits).
|
||||
|
||||
:type number: numbers.Real
|
||||
:type ndigits: numbers.Real | None
|
||||
:rtype: float
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class slice(object):
|
||||
def __init__(self, start, stop=None, step=None):
|
||||
"""Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).
|
||||
|
||||
:type start: numbers.Integral
|
||||
:type stop: numbers.Integral | None
|
||||
:type step: numbers.Integral | None
|
||||
"""
|
||||
return
|
||||
|
||||
|
||||
def vars(object=None):
|
||||
"""Without arguments, equivalent to locals(). With an argument, equivalent
|
||||
to object.__dict__.
|
||||
|
||||
:rtype: dict[string, unknown]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class object:
|
||||
""" The most base type."""
|
||||
|
||||
@staticmethod
|
||||
def __new__(cls, *more):
|
||||
"""Create a new object.
|
||||
|
||||
:type cls: T
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class enumerate(object):
|
||||
"""enumerate object."""
|
||||
|
||||
def __init__(self, iterable, start=0):
|
||||
"""Create an enumerate object.
|
||||
|
||||
:type iterable: collections.Iterable[T]
|
||||
:type start: int | long
|
||||
:rtype: enumerate[int, T]
|
||||
"""
|
||||
pass
|
||||
|
||||
def next(self):
|
||||
"""Return the next value, or raise StopIteration.
|
||||
|
||||
:rtype: (int, T)
|
||||
"""
|
||||
pass
|
||||
|
||||
def __iter__(self):
|
||||
"""x.__iter__() <==> iter(x).
|
||||
|
||||
:rtype: enumerate[int, T]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
if __sys.version_info < (3,):
|
||||
class xrange(object):
|
||||
"""xrange object."""
|
||||
|
||||
def __init__(self, start, stop=None, step=None):
|
||||
"""Create an xrange object.
|
||||
|
||||
:type start: numbers.Integral
|
||||
:type stop: numbers.Integral | None
|
||||
:type step: numbers.Integral | None
|
||||
:rtype: xrange[int]
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,177 @@
|
||||
"""Skeleton for 'nose.tools' module."""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def assert_equal(first, second, msg=None):
|
||||
"""Fail if the two objects are unequal as determined by the '==' operator.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def assert_not_equal(first, second, msg=None):
|
||||
"""Fail if the two objects are equal as determined by the '==' operator.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def assert_true(expr, msg=None):
|
||||
"""Check that the expression is true."""
|
||||
pass
|
||||
|
||||
|
||||
def assert_false(expr, msg=None):
|
||||
"""Check that the expression is false."""
|
||||
pass
|
||||
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
def assert_is(expr1, expr2, msg=None):
|
||||
"""Just like assert_true(a is b), but with a nicer default message."""
|
||||
pass
|
||||
|
||||
def assert_is_not(expr1, expr2, msg=None):
|
||||
"""Just like assert_true(a is not b), but with a nicer default message.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_is_none(obj, msg=None):
|
||||
"""Same as assert_true(obj is None), with a nicer default message.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_is_not_none(obj, msg=None):
|
||||
"""Included for symmetry with assert_is_none."""
|
||||
pass
|
||||
|
||||
def assert_in(member, container, msg=None):
|
||||
"""Just like assert_true(a in b), but with a nicer default message."""
|
||||
pass
|
||||
|
||||
def assert_not_in(member, container, msg=None):
|
||||
"""Just like assert_true(a not in b), but with a nicer default message.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_is_instance(obj, cls, msg=None):
|
||||
"""Same as assert_true(isinstance(obj, cls)), with a nicer default
|
||||
message.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_not_is_instance(obj, cls, msg=None):
|
||||
"""Included for symmetry with assert_is_instance."""
|
||||
pass
|
||||
|
||||
|
||||
def assert_raises(excClass, callableObj=None, *args, **kwargs):
|
||||
"""Fail unless an exception of class excClass is thrown by callableObj when
|
||||
invoked with arguments args and keyword arguments kwargs.
|
||||
|
||||
If called with callableObj omitted or None, will return a
|
||||
context object used like this::
|
||||
|
||||
with assert_raises(SomeException):
|
||||
do_something()
|
||||
|
||||
:rtype: unittest.case._AssertRaisesContext | None
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
def assert_raises_regexp(expected_exception, expected_regexp,
|
||||
callable_obj=None, *args, **kwargs):
|
||||
"""Asserts that the message in a raised exception matches a regexp.
|
||||
|
||||
:rtype: unittest.case._AssertRaisesContext | None
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def assert_almost_equal(first, second, places=None, msg=None, delta=None):
|
||||
"""Fail if the two objects are unequal as determined by their difference
|
||||
rounded to the given number of decimal places (default 7) and comparing to
|
||||
zero, or by comparing that the between the two objects is more than the
|
||||
given delta.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def assert_not_almost_equal(first, second, places=None, msg=None, delta=None):
|
||||
"""Fail if the two objects are equal as determined by their difference
|
||||
rounded to the given number of decimal places (default 7) and comparing to
|
||||
zero, or by comparing that the between the two objects is less than the
|
||||
given delta.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
def assert_greater(a, b, msg=None):
|
||||
"""Just like assert_true(a > b), but with a nicer default message."""
|
||||
pass
|
||||
|
||||
def assert_greater_equal(a, b, msg=None):
|
||||
"""Just like assert_true(a >= b), but with a nicer default message."""
|
||||
pass
|
||||
|
||||
def assert_less(a, b, msg=None):
|
||||
"""Just like assert_true(a < b), but with a nicer default message."""
|
||||
pass
|
||||
|
||||
def assert_less_equal(a, b, msg=None):
|
||||
"""Just like self.assertTrue(a <= b), but with a nicer default
|
||||
message.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_regexp_matches(text, expected_regexp, msg=None):
|
||||
"""Fail the test unless the text matches the regular expression."""
|
||||
pass
|
||||
|
||||
def assert_not_regexp_matches(text, unexpected_regexp, msg=None):
|
||||
"""Fail the test if the text matches the regular expression."""
|
||||
pass
|
||||
|
||||
def assert_items_equal(expected_seq, actual_seq, msg=None):
|
||||
"""An unordered sequence specific comparison. It asserts that
|
||||
actual_seq and expected_seq have the same element counts.
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_dict_contains_subset(expected, actual, msg=None):
|
||||
"""Checks whether actual is a superset of expected."""
|
||||
pass
|
||||
|
||||
def assert_multi_line_equal(first, second, msg=None):
|
||||
"""Assert that two multi-line strings are equal."""
|
||||
pass
|
||||
|
||||
def assert_sequence_equal(seq1, seq2, msg=None, seq_type=None):
|
||||
"""An equality assertion for ordered sequences (like lists and tuples).
|
||||
"""
|
||||
pass
|
||||
|
||||
def assert_list_equal(list1, list2, msg=None):
|
||||
"""A list-specific equality assertion."""
|
||||
pass
|
||||
|
||||
def assert_tuple_equal(tuple1, tuple2, msg=None):
|
||||
"""A tuple-specific equality assertion."""
|
||||
pass
|
||||
|
||||
def assert_set_equal(set1, set2, msg=None):
|
||||
"""A set-specific equality assertion."""
|
||||
pass
|
||||
|
||||
def assert_dict_equal(d1, d2, msg=None):
|
||||
"""A dict-specific equality assertion."""
|
||||
pass
|
||||
|
||||
|
||||
assert_equals = assert_equal
|
||||
assert_not_equals = assert_not_equal
|
||||
assert_almost_equals = assert_almost_equal
|
||||
assert_not_almost_equals = assert_not_almost_equal
|
||||
@@ -0,0 +1,277 @@
|
||||
"""Skeleton for 're' stdlib module."""
|
||||
|
||||
|
||||
def compile(pattern, flags=0):
|
||||
"""Compile a regular expression pattern, returning a pattern object.
|
||||
|
||||
:type pattern: bytes | unicode
|
||||
:type flags: int
|
||||
:rtype: __Regex
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def search(pattern, string, flags=0):
|
||||
"""Scan through string looking for a match, and return a corresponding
|
||||
match instance. Return None if no position in the string matches.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type string: T <= bytes | unicode
|
||||
:type flags: int
|
||||
:rtype: __Match[T] | None
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def match(pattern, string, flags=0):
|
||||
"""Matches zero or more characters at the beginning of the string.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type string: T <= bytes | unicode
|
||||
:type flags: int
|
||||
:rtype: __Match[T] | None
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def split(pattern, string, maxsplit=0, flags=0):
|
||||
"""Split string by the occurrences of pattern.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type string: T <= bytes | unicode
|
||||
:type maxsplit: int
|
||||
:type flags: int
|
||||
:rtype: list[T]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def findall(pattern, string, flags=0):
|
||||
"""Return a list of all non-overlapping matches of pattern in string.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type string: T <= bytes | unicode
|
||||
:type flags: int
|
||||
:rtype: list[T]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def finditer(pattern, string, flags=0):
|
||||
"""Return an iterator over all non-overlapping matches for the pattern in
|
||||
string. For each match, the iterator returns a match object.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type string: T <= bytes | unicode
|
||||
:type flags: int
|
||||
:rtype: collections.Iterable[__Match[T]]
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def sub(pattern, repl, string, count=0, flags=0):
|
||||
"""Return the string obtained by replacing the leftmost non-overlapping
|
||||
occurrences of pattern in string by the replacement repl.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type repl: bytes | unicode | collections.Callable
|
||||
:type string: T <= bytes | unicode
|
||||
:type count: int
|
||||
:type flags: int
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def subn(pattern, repl, string, count=0, flags=0):
|
||||
"""Return the tuple (new_string, number_of_subs_made) found by replacing
|
||||
the leftmost non-overlapping occurrences of pattern with the
|
||||
replacement repl.
|
||||
|
||||
:type pattern: bytes | unicode | __Regex
|
||||
:type repl: bytes | unicode | collections.Callable
|
||||
:type string: T <= bytes | unicode
|
||||
:type count: int
|
||||
:type flags: int
|
||||
:rtype: (T, int)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def escape(string):
|
||||
"""Escape all the characters in pattern except ASCII letters and numbers.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type: T
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class __Regex(object):
|
||||
"""Mock class for a regular expression pattern object."""
|
||||
|
||||
def __init__(self, flags, groups, groupindex, pattern):
|
||||
"""Create a new pattern object.
|
||||
|
||||
:type flags: int
|
||||
:type groups: int
|
||||
:type groupindex: dict[bytes | unicode, int]
|
||||
:type pattern: bytes | unicode
|
||||
"""
|
||||
self.flags = flags
|
||||
self.groups = groups
|
||||
self.groupindex = groupindex
|
||||
self.pattern = pattern
|
||||
|
||||
def search(self, string, pos=0, endpos=-1):
|
||||
"""Scan through string looking for a match, and return a corresponding
|
||||
match instance. Return None if no position in the string matches.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type pos: int
|
||||
:type endpos: int
|
||||
:rtype: __Match[T] | None
|
||||
"""
|
||||
pass
|
||||
|
||||
def match(self, string, pos=0, endpos=-1):
|
||||
"""Matches zero | more characters at the beginning of the string.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type pos: int
|
||||
:type endpos: int
|
||||
:rtype: __Match[T] | None
|
||||
"""
|
||||
pass
|
||||
|
||||
def split(self, string, maxsplit=0):
|
||||
"""Split string by the occurrences of pattern.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type maxsplit: int
|
||||
:rtype: list[T]
|
||||
"""
|
||||
pass
|
||||
|
||||
def findall(self, string, pos=0, endpos=-1):
|
||||
"""Return a list of all non-overlapping matches of pattern in string.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type pos: int
|
||||
:type endpos: int
|
||||
:rtype: list[T]
|
||||
"""
|
||||
pass
|
||||
|
||||
def finditer(self, string, pos=0, endpos=-1):
|
||||
"""Return an iterator over all non-overlapping matches for the
|
||||
pattern in string. For each match, the iterator returns a
|
||||
match object.
|
||||
|
||||
:type string: T <= bytes | unicode
|
||||
:type pos: int
|
||||
:type endpos: int
|
||||
:rtype: collections.Iterable[__Match[T]]
|
||||
"""
|
||||
pass
|
||||
|
||||
def sub(self, repl, string, count=0):
|
||||
"""Return the string obtained by replacing the leftmost non-overlapping
|
||||
occurrences of pattern in string by the replacement repl.
|
||||
|
||||
:type repl: bytes | unicode | collections.Callable
|
||||
:type string: T <= bytes | unicode
|
||||
:type count: int
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
def subn(self, repl, string, count=0):
|
||||
"""Return the tuple (new_string, number_of_subs_made) found by replacing
|
||||
the leftmost non-overlapping occurrences of pattern with the
|
||||
replacement repl.
|
||||
|
||||
:type repl: bytes | unicode | collections.Callable
|
||||
:type string: T <= bytes | unicode
|
||||
:type count: int
|
||||
:rtype: (T, int)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class __Match(object):
|
||||
"""Mock class for a match object."""
|
||||
|
||||
def __init__(self, pos, endpos, lastindex, lastgroup, re, string):
|
||||
"""Create a new match object.
|
||||
|
||||
:type pos: int
|
||||
:type endpos: int
|
||||
:type lastindex: int | None
|
||||
:type lastgroup: int | bytes | unicode | None
|
||||
:type re: __Regex
|
||||
:type string: bytes | unicode
|
||||
:rtype: __Match[T]
|
||||
"""
|
||||
self.pos = pos
|
||||
self.endpos = endpos
|
||||
self.lastindex = lastindex
|
||||
self.lastgroup = lastgroup
|
||||
self.re = re
|
||||
self.string = string
|
||||
|
||||
def expand(self, template):
|
||||
"""Return the string obtained by doing backslash substitution on the
|
||||
template string template.
|
||||
|
||||
:type template: T
|
||||
:rtype: T
|
||||
"""
|
||||
pass
|
||||
|
||||
def group(self, *args):
|
||||
"""Return one or more subgroups of the match.
|
||||
|
||||
:rtype: T | tuple
|
||||
"""
|
||||
pass
|
||||
|
||||
def groups(self, default=None):
|
||||
"""Return a tuple containing all the subgroups of the match, from 1 up
|
||||
to however many groups are in the pattern.
|
||||
|
||||
:rtype: tuple
|
||||
"""
|
||||
pass
|
||||
|
||||
def groupdict(self, default=None):
|
||||
"""Return a dictionary containing all the named subgroups of the match,
|
||||
keyed by the subgroup name.
|
||||
|
||||
:rtype: dict[bytes | unicode, T]
|
||||
"""
|
||||
pass
|
||||
|
||||
def start(self, group=0):
|
||||
"""Return the index of the start of the substring matched by group.
|
||||
|
||||
:type group: int | bytes | unicode
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
def end(self, group=0):
|
||||
"""Return the index of the end of the substring matched by group.
|
||||
|
||||
:type group: int | bytes | unicode
|
||||
:rtype: int
|
||||
"""
|
||||
pass
|
||||
|
||||
def span(self, group=0):
|
||||
"""Return a 2-tuple (start, end) for the substring matched by group.
|
||||
|
||||
:type group: int | bytes | unicode
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
pass
|
||||
@@ -4,6 +4,7 @@
|
||||
<resource-bundle>com.jetbrains.python.PyBundle</resource-bundle>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<nameSuggestionProvider implementation="com.jetbrains.python.refactoring.PyNameSuggestionProvider"/>
|
||||
<methodNavigationOffsetProvider implementation="com.jetbrains.python.codeInsight.PyMethodNavigationOffsetProvider"/>
|
||||
<copyPastePreProcessor implementation="com.jetbrains.python.editor.PythonCopyPasteProcessor"/>
|
||||
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
|
||||
@@ -324,6 +325,7 @@
|
||||
<localInspection language="Python" shortName="PyDocstringTypesInspection" bundle="com.jetbrains.python.PyBundle" key="INSP.NAME.docstring.types" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WEAK WARNING" implementationClass="com.jetbrains.python.inspections.PyDocstringTypesInspection"/>
|
||||
<localInspection language="Python" shortName="PyShadowingBuiltinsInspection" displayName="Shadowing built-ins" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyShadowingBuiltinsInspection"/>
|
||||
<localInspection language="Python" shortName="PyAbstractClassInspection" displayName="Class must implement all abstract methods" groupKey="INSP.GROUP.python" enabledByDefault="true" level="WARNING" implementationClass="com.jetbrains.python.inspections.PyAbstractClassInspection"/>
|
||||
<localInspection language="Python" shortName="PyPep8NamingInspection" displayName="PEP 8 naming convention violation" groupKey="INSP.GROUP.python" enabledByDefault="true" level="INFO" implementationClass="com.jetbrains.python.inspections.PyPep8NamingInspection"/>
|
||||
|
||||
<liveTemplateContext implementation="com.jetbrains.python.codeInsight.liveTemplates.PythonTemplateContextType"/>
|
||||
<liveTemplateMacro implementation="com.jetbrains.python.codeInsight.liveTemplates.CollectionElementNameMacro"/>
|
||||
@@ -570,6 +572,9 @@
|
||||
<!-- Packaging -->
|
||||
<keywordArgumentProvider implementation="com.jetbrains.python.packaging.setupPy.SetupKeywordArgumentProvider"/>
|
||||
|
||||
<!-- PyQt -->
|
||||
<typeProvider implementation="com.jetbrains.pyqt.PyQtTypeProvider"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
<project-components>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.jetbrains.pyqt;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
|
||||
import com.jetbrains.python.psi.types.*;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyQtTypeProvider extends PyTypeProviderBase {
|
||||
private static final String ourQtBoundSignal = "QtCore.pyqtBoundSignal";
|
||||
private static final String ourQt4Signal = "pyqtSignal";
|
||||
|
||||
@Override
|
||||
public PyType getReferenceExpressionType(PyReferenceExpression referenceExpression, TypeEvalContext context) {
|
||||
final PsiPolyVariantReference reference = referenceExpression.getReference();
|
||||
final PsiElement element = reference.resolve();
|
||||
if (element instanceof PyTypedElement) {
|
||||
final PyType type = context.getType((PyTypedElement)element);
|
||||
if (type instanceof PyClassType) {
|
||||
final String classQName = ((PyClassType)type).getClassQName();
|
||||
if (classQName != null && classQName.startsWith("PyQt")) {
|
||||
final PyQualifiedName name = PyQualifiedName.fromDottedString(classQName);
|
||||
final String qtVersion = name.getComponents().get(0);
|
||||
if (ourQt4Signal.equals(name.getLastComponent())) {
|
||||
final PyClass aClass = PyClassNameIndex.findClass(qtVersion + "." + ourQtBoundSignal, referenceExpression.getProject());
|
||||
if (aClass != null)
|
||||
return new PyClassTypeImpl(aClass, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyFunctionType) {
|
||||
final Callable callable = ((PyFunctionType)type).getCallable();
|
||||
if (callable instanceof PyFunction) {
|
||||
final String qualifiedName = callable.getQualifiedName();
|
||||
if (qualifiedName != null && qualifiedName.startsWith("PyQt")){
|
||||
final PyQualifiedName name = PyQualifiedName.fromDottedString(qualifiedName);
|
||||
final String qtVersion = name.getComponents().get(0);
|
||||
final String docstring = ((PyFunction)callable).getDocStringValue();
|
||||
if (docstring != null && docstring.contains("[signal]")) {
|
||||
final PyClass aClass = PyClassNameIndex.findClass(qtVersion + "." + ourQtBoundSignal, referenceExpression.getProject());
|
||||
if (aClass != null)
|
||||
return new PyClassTypeImpl(aClass, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.codeInsight.imports;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtilCore;
|
||||
@@ -47,8 +48,9 @@ public class AddImportHelper {
|
||||
boolean skippedOverImports = false;
|
||||
boolean skippedOverDoc = false;
|
||||
PsiElement seeker = feeler;
|
||||
final boolean isInjected = InjectedLanguageManager.getInstance(feeler.getProject()).isInjectedFragment(feeler.getContainingFile());
|
||||
do {
|
||||
if (feeler instanceof PyImportStatementBase) {
|
||||
if (feeler instanceof PyImportStatementBase && !isInjected) {
|
||||
if (nameToImport != null && priority != null && shouldInsertBefore(file, (PyImportStatementBase)feeler, nameToImport, priority)) {
|
||||
break;
|
||||
}
|
||||
@@ -172,17 +174,21 @@ public class AddImportHelper {
|
||||
* @param asName optional name for 'as' clause
|
||||
*/
|
||||
public static void addImportFromStatement(PsiFile file, String from, String name, @Nullable String asName, ImportPriority priority) {
|
||||
String asClause;
|
||||
if (asName == null) {
|
||||
asClause = "";
|
||||
}
|
||||
else {
|
||||
asClause = " as " + asName;
|
||||
}
|
||||
String asClause = asName == null ? "" : " as " + asName;
|
||||
|
||||
final PyFromImportStatement importNodeToInsert = PyElementGenerator.getInstance(file.getProject()).createFromText(
|
||||
LanguageLevel.forElement(file), PyFromImportStatement.class, "from " + from + " import " + name + asClause);
|
||||
try {
|
||||
file.addBefore(importNodeToInsert, getInsertPosition(file, from, priority));
|
||||
if (InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file)) {
|
||||
final PsiElement element = file.addBefore(importNodeToInsert, getInsertPosition(file, from, priority));
|
||||
PsiElement whitespace = element.getNextSibling();
|
||||
if (!(whitespace instanceof PsiWhiteSpace))
|
||||
whitespace = PsiParserFacade.SERVICE.getInstance(file.getProject()).createWhiteSpaceFromText(" >>> ");
|
||||
file.addBefore(whitespace, element);
|
||||
}
|
||||
else {
|
||||
file.addBefore(importNodeToInsert, getInsertPosition(file, from, priority));
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -34,21 +35,28 @@ import java.util.List;
|
||||
* @author vlan
|
||||
*/
|
||||
public class PyUserSkeletonsUtil {
|
||||
public static final String USER_SKELETONS_DIR = "python-skeletons";
|
||||
@Nullable private static VirtualFile ourUserSkeletonsDirectory;
|
||||
|
||||
@NotNull
|
||||
public static String getUserSkeletonsPath() {
|
||||
if (ApplicationManager.getApplication().isInternal()) {
|
||||
return StringUtil.join(new String[] {PathManager.getHomePath(), "python", "helpers", "user-skeletons"}, File.separator);
|
||||
}
|
||||
// TODO: Add the possibility to put skeletons into PathManager.getSystemPath() + "/user-skeletons"
|
||||
return PythonHelpersLocator.getHelperPath("user-skeletons");
|
||||
private static List<String> getPossibleUserSkeletonsPaths() {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
result.add(PathManager.getConfigPath() + File.separator + USER_SKELETONS_DIR);
|
||||
result.add(ApplicationManager.getApplication().isInternal()
|
||||
? StringUtil.join(new String[]{PathManager.getHomePath(), "python", "helpers", USER_SKELETONS_DIR}, File.separator)
|
||||
: PythonHelpersLocator.getHelperPath(USER_SKELETONS_DIR));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile getUserSkeletonsDirectory() {
|
||||
if (ourUserSkeletonsDirectory == null) {
|
||||
ourUserSkeletonsDirectory = LocalFileSystem.getInstance().findFileByPath(getUserSkeletonsPath());
|
||||
for (String path : getPossibleUserSkeletonsPaths()) {
|
||||
ourUserSkeletonsDirectory = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
|
||||
if (ourUserSkeletonsDirectory != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ourUserSkeletonsDirectory;
|
||||
}
|
||||
@@ -75,7 +83,7 @@ public class PyUserSkeletonsUtil {
|
||||
if (sdk != null) {
|
||||
final Project project = foothold.getProject();
|
||||
final PythonSdkPathCache cache = PythonSdkPathCache.getInstance(project, sdk);
|
||||
final PyQualifiedName cacheQName = PyQualifiedName.fromDottedString("user-skeletons." + qName);
|
||||
final PyQualifiedName cacheQName = PyQualifiedName.fromDottedString(USER_SKELETONS_DIR + "." + qName);
|
||||
final List<PsiElement> results = cache.get(cacheQName);
|
||||
if (results != null) {
|
||||
final PsiElement element = results.isEmpty() ? null : results.get(0);
|
||||
@@ -101,7 +109,7 @@ public class PyUserSkeletonsUtil {
|
||||
}
|
||||
|
||||
public static void addUserSkeletonsRoot(@NotNull SdkModificator sdkModificator) {
|
||||
final VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByPath(getUserSkeletonsPath());
|
||||
final VirtualFile root = getUserSkeletonsDirectory();
|
||||
if (root != null) {
|
||||
sdkModificator.addRoot(root, OrderRootType.CLASSES);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.jetbrains.python.documentation.doctest;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyImportStatement;
|
||||
import com.jetbrains.python.psi.PyFromImportStatement;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import com.jetbrains.python.psi.impl.PyReferenceExpressionImpl;
|
||||
import com.jetbrains.python.psi.impl.references.PyImportReference;
|
||||
import com.jetbrains.python.psi.impl.references.PyQualifiedReference;
|
||||
@@ -27,8 +29,10 @@ public class PyDocReferenceExpression extends PyReferenceExpressionImpl {
|
||||
if (qualifier != null) {
|
||||
return new PyQualifiedReference(this, context);
|
||||
}
|
||||
else if (PsiTreeUtil.getParentOfType(this, PyImportStatement.class) != null)
|
||||
return new PyImportReference(this, context);
|
||||
final PsiElement importParent = PsiTreeUtil.getParentOfType(this, PyImportElement.class, PyFromImportStatement.class);
|
||||
if (importParent != null) {
|
||||
return PyImportReference.forElement(this, importParent, context);
|
||||
}
|
||||
return new PyDocReference(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -11,4 +11,9 @@ public class PyDocstringTokenSetContributor extends PythonTokenSetContributor {
|
||||
public TokenSet getExpressionTokens() {
|
||||
return TokenSet.orSet(super.getExpressionTokens(), TokenSet.create(PyDocstringTokenTypes.DOC_REFERENCE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenSet getReferenceExpressionTokens() {
|
||||
return TokenSet.orSet(super.getExpressionTokens(), TokenSet.create(PyDocstringTokenTypes.DOC_REFERENCE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyPep8NamingInspection extends PyInspection {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean isOnTheFly,
|
||||
@NotNull LocalInspectionToolSession session) {
|
||||
return new Visitor(holder, session);
|
||||
}
|
||||
|
||||
public static class Visitor extends PyInspectionVisitor {
|
||||
Pattern LOWERCASE_REGEX = Pattern.compile("[_a-z][_a-z0-9]*");
|
||||
Pattern UPPERCASE_REGEX = Pattern.compile("[_A-Z][_A-Z0-9]*");
|
||||
Pattern MIXEDCASE_REGEX = Pattern.compile("_?[A-Z][a-zA-Z0-9]*");
|
||||
|
||||
public Visitor(@NotNull final ProblemsHolder holder, LocalInspectionToolSession session) {
|
||||
super(holder, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
|
||||
final PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class, true, PyClass.class);
|
||||
if (function == null) return;
|
||||
for (PyExpression expression : node.getTargets()) {
|
||||
final String name = expression.getName();
|
||||
if (name == null) continue;
|
||||
if (!LOWERCASE_REGEX.matcher(name).matches() && !name.startsWith("_")) {
|
||||
registerProblem(expression, "Variable in function should be lowercase", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyParameter(PyParameter node) {
|
||||
final String name = node.getName();
|
||||
if (name == null) return;
|
||||
if (!LOWERCASE_REGEX.matcher(name).matches()) {
|
||||
registerProblem(node, "Argument name should be lowercase", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyFunction(PyFunction node) {
|
||||
final PyClass containingClass = node.getContainingClass();
|
||||
final String name = node.getName();
|
||||
if (name == null) return;
|
||||
if (containingClass != null && name.startsWith("__") && name.endsWith("__")) {
|
||||
return;
|
||||
}
|
||||
if (!LOWERCASE_REGEX.matcher(name).matches()) {
|
||||
final ASTNode nameNode = node.getNameNode();
|
||||
if (nameNode != null)
|
||||
registerProblem(nameNode.getPsi(), "Function name should be lowercase", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyClass(PyClass node) {
|
||||
final String name = node.getName();
|
||||
if (name == null) return;
|
||||
if (!MIXEDCASE_REGEX.matcher(name).matches()) {
|
||||
final ASTNode nameNode = node.getNameNode();
|
||||
if (nameNode != null)
|
||||
registerProblem(nameNode.getPsi(), "Class names should use CamelCase convention", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyImportElement(PyImportElement node) {
|
||||
final String asName = node.getAsName();
|
||||
final PyQualifiedName importedQName = node.getImportedQName();
|
||||
if (importedQName == null) return;
|
||||
final String name = importedQName.toString();
|
||||
|
||||
if (asName == null || name == null) return;
|
||||
if (UPPERCASE_REGEX.matcher(name).matches()) {
|
||||
if (!UPPERCASE_REGEX.matcher(asName).matches()) {
|
||||
registerProblem(node.getAsNameElement(), "Constant variable imported as non constant", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
else if (LOWERCASE_REGEX.matcher(name).matches()) {
|
||||
if (!LOWERCASE_REGEX.matcher(asName).matches()) {
|
||||
registerProblem(node.getAsNameElement(), "Lowercase variable imported as non lowercase", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
else if (LOWERCASE_REGEX.matcher(asName).matches()) {
|
||||
registerProblem(node.getAsNameElement(), "CamelCase variable imported as lowercase", new PyRenameElementQuickFix());
|
||||
}
|
||||
else if (UPPERCASE_REGEX.matcher(asName).matches()) {
|
||||
registerProblem(node.getAsNameElement(), "CamelCase variable imported as constant", new PyRenameElementQuickFix());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.PsiSearchHelper;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.rename.PsiElementRenameHandler;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
|
||||
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import com.jetbrains.python.psi.PyTargetExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: ktisha
|
||||
*/
|
||||
public class PyRenameElementQuickFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Rename element";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Rename element";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
final PsiNameIdentifierOwner nameOwner = element instanceof PsiNameIdentifierOwner ?
|
||||
(PsiNameIdentifierOwner)element :
|
||||
PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner.class, true);
|
||||
if (nameOwner != null) {
|
||||
final VirtualFile virtualFile = nameOwner.getContainingFile().getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
final Editor editor = FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile), true);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
renameInUnitTestMode(project, nameOwner, editor);
|
||||
}
|
||||
else {
|
||||
if (checkLocalScope(element) != null && (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression)) {
|
||||
new VariableInplaceRenamer(nameOwner, editor).performInplaceRename();
|
||||
}
|
||||
else {
|
||||
PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiElement checkLocalScope(PsiElement element) {
|
||||
final SearchScope searchScope = PsiSearchHelper.SERVICE.getInstance(element.getProject()).getUseScope(element);
|
||||
if (searchScope instanceof LocalSearchScope) {
|
||||
final PsiElement[] elements = ((LocalSearchScope)searchScope).getScope();
|
||||
return PsiTreeUtil.findCommonParent(elements);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void renameInUnitTestMode(@NotNull Project project, @NotNull PsiNameIdentifierOwner nameOwner,
|
||||
@Nullable Editor editor) {
|
||||
final PsiElement substitution = RenamePsiElementProcessor.forElement(nameOwner).substituteElementToRename(nameOwner, editor);
|
||||
if (substitution != null) {
|
||||
new RenameProcessor(project, substitution, "a", false, false).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,10 @@
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.rename.PsiElementRenameHandler;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
|
||||
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -81,52 +67,5 @@ public class PyShadowingBuiltinsInspection extends PyInspection {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class PyRenameElementQuickFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Rename element";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Rename element";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
final PsiNameIdentifierOwner nameOwner = element instanceof PsiNameIdentifierOwner ?
|
||||
(PsiNameIdentifierOwner)element :
|
||||
PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner.class, true);
|
||||
if (nameOwner != null) {
|
||||
final VirtualFile virtualFile = nameOwner.getContainingFile().getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
final Editor editor = FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile), true);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
renameInUnitTestMode(project, nameOwner, editor);
|
||||
}
|
||||
else {
|
||||
if (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression) {
|
||||
new VariableInplaceRenamer(nameOwner, editor).performInplaceRename();
|
||||
}
|
||||
else {
|
||||
PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void renameInUnitTestMode(@NotNull Project project, @NotNull PsiNameIdentifierOwner nameOwner,
|
||||
@Nullable Editor editor) {
|
||||
final PsiElement substitution = RenamePsiElementProcessor.forElement(nameOwner).substituteElementToRename(nameOwner, editor);
|
||||
if (substitution != null) {
|
||||
new RenameProcessor(project, substitution, "a", false, false).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* @author max
|
||||
*/
|
||||
package com.jetbrains.python.refactoring;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.rename.NameSuggestionProvider;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyNameSuggestionProvider implements NameSuggestionProvider {
|
||||
public SuggestedNameInfo getSuggestedNames(PsiElement element, PsiElement nameSuggestionContext, Set<String> result) {
|
||||
if (!(element instanceof PyElement)) return null;
|
||||
final String name = ((PyElement)element).getName();
|
||||
if (name == null) return null;
|
||||
|
||||
if (element instanceof PyClass) {
|
||||
result.add(toCamelCase(name, true));
|
||||
}
|
||||
else if (element instanceof PyFunction || element instanceof PyParameter) {
|
||||
result.add(name.toLowerCase());
|
||||
}
|
||||
else {
|
||||
result.add(name.toLowerCase());
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) return null;
|
||||
result.add(name.toUpperCase());
|
||||
result.add(toCamelCase(name, false));
|
||||
}
|
||||
return SuggestedNameInfo.NULL_INFO;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected String toCamelCase(@NotNull final String name, boolean uppercaseFirstLetter) {
|
||||
final List<String> strings = StringUtil.split(name, "_");
|
||||
if (strings.size() > 0) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
String str = strings.get(0).toLowerCase();
|
||||
if (uppercaseFirstLetter) str = StringUtil.capitalize(str);
|
||||
buf.append(str);
|
||||
for (int i = 1; i < strings.size(); i++) {
|
||||
buf.append(StringUtil.capitalize(strings.get(i).toLowerCase()));
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.jetbrains.python.refactoring.classes;
|
||||
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
@@ -348,7 +349,11 @@ public class PyClassRefactoringUtil {
|
||||
}
|
||||
if (deleteImportElement) {
|
||||
if (importStatement.getImportElements().length == 1) {
|
||||
importStatement.delete();
|
||||
final boolean isInjected = InjectedLanguageManager.getInstance(importElement.getProject()).isInjectedFragment(importElement.getContainingFile());
|
||||
if (!isInjected)
|
||||
importStatement.delete();
|
||||
else
|
||||
deleteImportStatementFromInjected(importStatement);
|
||||
}
|
||||
else {
|
||||
importElement.delete();
|
||||
@@ -358,6 +363,13 @@ public class PyClassRefactoringUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteImportStatementFromInjected(@NotNull final PyImportStatementBase importStatement) {
|
||||
final PsiElement sibling = importStatement.getPrevSibling();
|
||||
importStatement.delete();
|
||||
if (sibling instanceof PsiWhiteSpace)
|
||||
sibling.delete();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getOriginalName(@NotNull PsiNamedElement element) {
|
||||
if (element instanceof PyFile) {
|
||||
|
||||
@@ -77,8 +77,6 @@ public class PyMoveFileHandler extends MoveFileHandler {
|
||||
for (UsageInfo usage : usages) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element != null) {
|
||||
if (InjectedLanguageManager.getInstance(element.getProject()).isInjectedFragment(element.getContainingFile()))
|
||||
continue;
|
||||
final PsiNamedElement newElement = element.getCopyableUserData(REFERENCED_ELEMENT);
|
||||
element.putCopyableUserData(REFERENCED_ELEMENT, null);
|
||||
if (newElement != null) {
|
||||
@@ -111,7 +109,9 @@ public class PyMoveFileHandler extends MoveFileHandler {
|
||||
if (!updatedFiles.isEmpty()) {
|
||||
final PyImportOptimizer optimizer = new PyImportOptimizer();
|
||||
for (PsiFile file : updatedFiles) {
|
||||
optimizer.processFile(file).run();
|
||||
final boolean injectedFragment = InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file);
|
||||
if (!injectedFragment)
|
||||
optimizer.processFile(file).run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,10 @@ public class PythonSdkUpdater implements StartupActivity {
|
||||
private static void updateSysPath(final Sdk sdk) throws InvalidSdkException {
|
||||
long start_time = System.currentTimeMillis();
|
||||
final List<String> sysPath = PythonSdkType.getSysPath(sdk.getHomePath());
|
||||
sysPath.add(PyUserSkeletonsUtil.getUserSkeletonsPath());
|
||||
final VirtualFile file = PyUserSkeletonsUtil.getUserSkeletonsDirectory();
|
||||
if (file != null) {
|
||||
sysPath.add(file.getPath());
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -422,16 +422,18 @@ public class PyParameterInfoTest extends LightMarkedTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupUIComponentPresentation(String[] texts, EnumSet<Flag>[] flags, Color background) {
|
||||
public String setupUIComponentPresentation(String[] texts, EnumSet<Flag>[] flags, Color background) {
|
||||
assert texts.length == flags.length;
|
||||
myTexts = texts;
|
||||
myFlags = flags;
|
||||
return StringUtil.join(texts, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupUIComponentPresentation(String text, int highlightStartOffset, int highlightEndOffset, boolean isDisabled,
|
||||
boolean strikeout, boolean isDisabledBeforeHighlight, Color background) {
|
||||
public String setupUIComponentPresentation(String text, int highlightStartOffset, int highlightEndOffset, boolean isDisabled,
|
||||
boolean strikeout, boolean isDisabledBeforeHighlight, Color background) {
|
||||
// nothing, we don't use it
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user