From 057c23e3f4ac72dd942522317adcf0612889ea3e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Sun, 6 Sep 2015 21:08:45 +0300 Subject: [PATCH] fixed PY-14822 Show external documentation about Python keywords added builtin documentation for python keywords --- python/helpers/tools/python_keywords/False | 5 + python/helpers/tools/python_keywords/None | 6 + python/helpers/tools/python_keywords/True | 5 + .../helpers/tools/python_keywords/__debug__ | 5 + python/helpers/tools/python_keywords/and | 27 +++++ python/helpers/tools/python_keywords/as | 96 +++++++++++++++ python/helpers/tools/python_keywords/assert | 28 +++++ python/helpers/tools/python_keywords/break | 16 +++ python/helpers/tools/python_keywords/class | 93 +++++++++++++++ python/helpers/tools/python_keywords/continue | 13 +++ python/helpers/tools/python_keywords/def | 102 ++++++++++++++++ python/helpers/tools/python_keywords/del | 21 ++++ python/helpers/tools/python_keywords/elif | 14 +++ python/helpers/tools/python_keywords/else | 14 +++ python/helpers/tools/python_keywords/except | 109 ++++++++++++++++++ python/helpers/tools/python_keywords/exec | 43 +++++++ python/helpers/tools/python_keywords/finally | 109 ++++++++++++++++++ python/helpers/tools/python_keywords/for | 55 +++++++++ python/helpers/tools/python_keywords/from | 96 +++++++++++++++ python/helpers/tools/python_keywords/global | 28 +++++ python/helpers/tools/python_keywords/if | 14 +++ python/helpers/tools/python_keywords/import | 96 +++++++++++++++ python/helpers/tools/python_keywords/in | 97 ++++++++++++++++ python/helpers/tools/python_keywords/is | 97 ++++++++++++++++ python/helpers/tools/python_keywords/lambda | 17 +++ python/helpers/tools/python_keywords/nonlocal | 25 ++++ python/helpers/tools/python_keywords/not | 27 +++++ python/helpers/tools/python_keywords/or | 27 +++++ python/helpers/tools/python_keywords/pass | 14 +++ python/helpers/tools/python_keywords/raise | 66 +++++++++++ python/helpers/tools/python_keywords/return | 18 +++ python/helpers/tools/python_keywords/try | 109 ++++++++++++++++++ python/helpers/tools/python_keywords/while | 17 +++ python/helpers/tools/python_keywords/with | 69 +++++++++++ python/helpers/tools/python_keywords/yield | 25 ++++ .../documentation/PyDocumentationBuilder.java | 34 +++++- .../PythonDocumentationProvider.java | 13 +++ python/testData/quickdoc/ReturnKeyword.html | 18 +++ python/testData/quickdoc/ReturnKeyword.py | 5 + .../com/jetbrains/python/PyQuickDocTest.java | 7 +- 40 files changed, 1676 insertions(+), 4 deletions(-) create mode 100644 python/helpers/tools/python_keywords/False create mode 100644 python/helpers/tools/python_keywords/None create mode 100644 python/helpers/tools/python_keywords/True create mode 100644 python/helpers/tools/python_keywords/__debug__ create mode 100644 python/helpers/tools/python_keywords/and create mode 100644 python/helpers/tools/python_keywords/as create mode 100644 python/helpers/tools/python_keywords/assert create mode 100644 python/helpers/tools/python_keywords/break create mode 100644 python/helpers/tools/python_keywords/class create mode 100644 python/helpers/tools/python_keywords/continue create mode 100644 python/helpers/tools/python_keywords/def create mode 100644 python/helpers/tools/python_keywords/del create mode 100644 python/helpers/tools/python_keywords/elif create mode 100644 python/helpers/tools/python_keywords/else create mode 100644 python/helpers/tools/python_keywords/except create mode 100644 python/helpers/tools/python_keywords/exec create mode 100644 python/helpers/tools/python_keywords/finally create mode 100644 python/helpers/tools/python_keywords/for create mode 100644 python/helpers/tools/python_keywords/from create mode 100644 python/helpers/tools/python_keywords/global create mode 100644 python/helpers/tools/python_keywords/if create mode 100644 python/helpers/tools/python_keywords/import create mode 100644 python/helpers/tools/python_keywords/in create mode 100644 python/helpers/tools/python_keywords/is create mode 100644 python/helpers/tools/python_keywords/lambda create mode 100644 python/helpers/tools/python_keywords/nonlocal create mode 100644 python/helpers/tools/python_keywords/not create mode 100644 python/helpers/tools/python_keywords/or create mode 100644 python/helpers/tools/python_keywords/pass create mode 100644 python/helpers/tools/python_keywords/raise create mode 100644 python/helpers/tools/python_keywords/return create mode 100644 python/helpers/tools/python_keywords/try create mode 100644 python/helpers/tools/python_keywords/while create mode 100644 python/helpers/tools/python_keywords/with create mode 100644 python/helpers/tools/python_keywords/yield create mode 100644 python/testData/quickdoc/ReturnKeyword.html create mode 100644 python/testData/quickdoc/ReturnKeyword.py diff --git a/python/helpers/tools/python_keywords/False b/python/helpers/tools/python_keywords/False new file mode 100644 index 000000000000..eef9f49650b8 --- /dev/null +++ b/python/helpers/tools/python_keywords/False @@ -0,0 +1,5 @@ +
+False +

The false value of the bool type. Assignments to False +are illegal and raise a SyntaxError.

+
\ No newline at end of file diff --git a/python/helpers/tools/python_keywords/None b/python/helpers/tools/python_keywords/None new file mode 100644 index 000000000000..8c58769d734d --- /dev/null +++ b/python/helpers/tools/python_keywords/None @@ -0,0 +1,6 @@ +
+None +

The sole value of the type NoneType. None is frequently used to +represent the absence of a value, as when default arguments are not passed to a +function. Assignments to None are illegal and raise a SyntaxError.

+
diff --git a/python/helpers/tools/python_keywords/True b/python/helpers/tools/python_keywords/True new file mode 100644 index 000000000000..07e263aa9e33 --- /dev/null +++ b/python/helpers/tools/python_keywords/True @@ -0,0 +1,5 @@ +
+True +

The true value of the bool type. Assignments to True +are illegal and raise a SyntaxError.

+
\ No newline at end of file diff --git a/python/helpers/tools/python_keywords/__debug__ b/python/helpers/tools/python_keywords/__debug__ new file mode 100644 index 000000000000..d21d156e07d9 --- /dev/null +++ b/python/helpers/tools/python_keywords/__debug__ @@ -0,0 +1,5 @@ +
+__debug__ +

This constant is true if Python was not started with an -O option. +See also the assert statement.

+
\ No newline at end of file diff --git a/python/helpers/tools/python_keywords/and b/python/helpers/tools/python_keywords/and new file mode 100644 index 000000000000..9b21ad3ed531 --- /dev/null +++ b/python/helpers/tools/python_keywords/and @@ -0,0 +1,27 @@ +
+

Boolean operations

+
+or_test  ::=  and_test | or_test "or" and_test
+and_test ::=  not_test | and_test "and" not_test
+not_test ::=  comparison | "not" not_test
+
+

In the context of Boolean operations, and also when expressions are used by +control flow statements, the following values are interpreted as false: +False, None, numeric zero of all types, and empty strings and containers +(including strings, tuples, lists, dictionaries, sets and frozensets). All +other values are interpreted as true. User-defined objects can customize their +truth value by providing a __bool__() method.

+

The operator not yields True if its argument is false, False +otherwise.

+

The expression x and y first evaluates x; if x is false, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

The expression x or y first evaluates x; if x is true, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

(Note that neither and nor or restrict the value and type +they return to False and True, but rather return the last evaluated +argument. This is sometimes useful, e.g., if s is a string that should be +replaced by a default value if it is empty, the expression s or 'foo' yields +the desired value. Because not has to create a new value, it +returns a boolean value regardless of the type of its argument +(for example, not 'foo' produces False rather than ''.)

+
diff --git a/python/helpers/tools/python_keywords/as b/python/helpers/tools/python_keywords/as new file mode 100644 index 000000000000..4636a318f756 --- /dev/null +++ b/python/helpers/tools/python_keywords/as @@ -0,0 +1,96 @@ +
+

The import statement

+
+import_stmt     ::=  "import" module ["as" name] ( "," module ["as" name] )*
+                     | "from" relative_module "import" identifier ["as" name]
+                     ( "," identifier ["as" name] )*
+                     | "from" relative_module "import" "(" identifier ["as" name]
+                     ( "," identifier ["as" name] )* [","] ")"
+                     | "from" module "import" "*"
+module          ::=  (identifier ".")* identifier
+relative_module ::=  "."* module | "."+
+name            ::=  identifier
+
+

The basic import statement (no from clause) is executed in two +steps:

+
    +
  1. find a module, loading and initializing it if necessary
  2. +
  3. define a name or names in the local namespace for the scope where +the import statement occurs.
  4. +
+

When the statement contains multiple clauses (separated by +commas) the two steps are carried out separately for each clause, just +as though the clauses had been separated out into individiual import +statements.

+

The details of the first step, finding and loading modules are described in +greater detail in the section on the import system, +which also describes the various types of packages and modules that can +be imported, as well as all the hooks that can be used to customize +the import system. Note that failures in this step may indicate either +that the module could not be located, or that an error occurred while +initializing the module, which includes execution of the module’s code.

+

If the requested module is retrieved successfully, it will be made +available in the local namespace in one of three ways:

+ +

The from form uses a slightly more complex process:

+
    +
  1. find the module specified in the from clause, loading and +initializing it if necessary;
  2. +
  3. for each of the identifiers specified in the import clauses:
      +
    1. check if the imported module has an attribute by that name
    2. +
    3. if not, attempt to import a submodule with that name and then +check the imported module again for that attribute
    4. +
    5. if the attribute is not found, ImportError is raised.
    6. +
    7. otherwise, a reference to that value is stored in the local namespace, +using the name in the as clause if it is present, +otherwise using the attribute name
    8. +
    +
  4. +
+

Examples:

+
import foo                 # foo imported and bound locally
+import foo.bar.baz         # foo.bar.baz imported, foo bound locally
+import foo.bar.baz as fbb  # foo.bar.baz imported and bound as fbb
+from foo.bar import baz    # foo.bar.baz imported and bound as baz
+from foo import attr       # foo imported and foo.attr bound as attr
+
+
+

If the list of identifiers is replaced by a star ('*'), all public +names defined in the module are bound in the local namespace for the scope +where the import statement occurs.

+

The public names defined by a module are determined by checking the module’s +namespace for a variable named __all__; if defined, it must be a sequence +of strings which are names defined or imported by that module. The names +given in __all__ are all considered public and are required to exist. If +__all__ is not defined, the set of public names includes all names found +in the module’s namespace which do not begin with an underscore character +('_'). __all__ should contain the entire public API. It is intended +to avoid accidentally exporting items that are not part of the API (such as +library modules which were imported and used within the module).

+

The wild card form of import — from module import * — is only allowed at +the module level. Attempting to use it in class or function definitions will +raise a SyntaxError.

+

When specifying what module to import you do not have to specify the absolute +name of the module. When a module or package is contained within another +package it is possible to make a relative import within the same top package +without having to mention the package name. By using leading dots in the +specified module or package after from you can specify how high to +traverse up the current package hierarchy without specifying exact names. One +leading dot means the current package where the module making the import +exists. Two dots means up one package level. Three dots is up two levels, etc. +So if you execute from . import mod from a module in the pkg package +then you will end up importing pkg.mod. If you execute from ..subpkg2 +import mod from within pkg.subpkg1 you will import pkg.subpkg2.mod. +The specification for relative imports is contained within PEP 328.

+

importlib.import_module() is provided to support applications that +determine dynamically the modules to be loaded.

diff --git a/python/helpers/tools/python_keywords/assert b/python/helpers/tools/python_keywords/assert new file mode 100644 index 000000000000..ae5e0bf73cb1 --- /dev/null +++ b/python/helpers/tools/python_keywords/assert @@ -0,0 +1,28 @@ +
+

The assert statement

+

Assert statements are a convenient way to insert debugging assertions into a +program:

+
+assert_stmt ::=  "assert" expression ["," expression]
+
+

The simple form, assert expression, is equivalent to

+
if __debug__:
+   if not expression: raise AssertionError
+
+
+

The extended form, assert expression1, expression2, is equivalent to

+
if __debug__:
+   if not expression1: raise AssertionError(expression2)
+
+
+

These equivalences assume that __debug__ and AssertionError refer to +the built-in variables with those names. In the current implementation, the +built-in variable __debug__ is True under normal circumstances, +False when optimization is requested (command line option -O). The current +code generator emits no code for an assert statement when optimization is +requested at compile time. Note that it is unnecessary to include the source +code for the expression that failed in the error message; it will be displayed +as part of the stack trace.

+

Assignments to __debug__ are illegal. The value for the built-in variable +is determined when the interpreter starts.

+
\ No newline at end of file diff --git a/python/helpers/tools/python_keywords/break b/python/helpers/tools/python_keywords/break new file mode 100644 index 000000000000..825385f2bd3a --- /dev/null +++ b/python/helpers/tools/python_keywords/break @@ -0,0 +1,16 @@ +
+

The break statement

+
+break_stmt ::=  "break"
+
+

break may only occur syntactically nested in a for or +while loop, but not nested in a function or class definition within +that loop.

+

It terminates the nearest enclosing loop, skipping the optional else +clause if the loop has one.

+

If a for loop is terminated by break, the loop control +target keeps its current value.

+

When break passes control out of a try statement with a +finally clause, that finally clause is executed before +really leaving the loop.

+
diff --git a/python/helpers/tools/python_keywords/class b/python/helpers/tools/python_keywords/class new file mode 100644 index 000000000000..a25d49a411e8 --- /dev/null +++ b/python/helpers/tools/python_keywords/class @@ -0,0 +1,93 @@ +
+

Class definitions

+

A class definition defines a class object (see section The standard type hierarchy):

+
+classdef    ::=  [decorators] "class" classname [inheritance] ":" suite
+inheritance ::=  "(" [parameter_list] ")"
+classname   ::=  identifier
+
+

A class definition is an executable statement. The inheritance list usually +gives a list of base classes (see Customizing class creation for more advanced uses), so +each item in the list should evaluate to a class object which allows +subclassing. Classes without an inheritance list inherit, by default, from the +base class object; hence,

+
class Foo:
+    pass
+
+
+

is equivalent to

+
class Foo(object):
+    pass
+
+
+

The class’s suite is then executed in a new execution frame (see Naming and binding), +using a newly created local namespace and the original global namespace. +(Usually, the suite contains mostly function definitions.) When the class’s +suite finishes execution, its execution frame is discarded but its local +namespace is saved. [4] A class object is then created using the inheritance +list for the base classes and the saved local namespace for the attribute +dictionary. The class name is bound to this class object in the original local +namespace.

+

Class creation can be customized heavily using metaclasses.

+

Classes can also be decorated: just like when decorating functions,

+
@f1(arg)
+@f2
+class Foo: pass
+
+
+

is equivalent to

+
class Foo: pass
+Foo = f1(arg)(f2(Foo))
+
+
+

The evaluation rules for the decorator expressions are the same as for function +decorators. The result must be a class object, which is then bound to the class +name.

+

Programmer’s note: Variables defined in the class definition are class +attributes; they are shared by instances. Instance attributes can be set in a +method with self.name = value. Both class and instance attributes are +accessible through the notation “self.name”, and an instance attribute hides +a class attribute with the same name when accessed in this way. Class +attributes can be used as defaults for instance attributes, but using mutable +values there can lead to unexpected results. Descriptors +can be used to create instance variables with different implementation details.

+
+

See also

+

PEP 3115 - Metaclasses in Python 3 +PEP 3129 - Class Decorators

+
+

Footnotes

+ + + + + +
[1]The exception is propagated to the invocation stack unless +there is a finally clause which happens to raise another +exception. That new exception causes the old one to be lost.
+ + + + + +
[2]Currently, control “flows off the end” except in the case of an exception +or the execution of a return, continue, or +break statement.
+ + + + + +
[3]A string literal appearing as the first statement in the function body is +transformed into the function’s __doc__ attribute and therefore the +function’s docstring.
+ + + + + +
[4]A string literal appearing as the first statement in the class body is +transformed into the namespace’s __doc__ item and therefore the class’s +docstring.
+
+
diff --git a/python/helpers/tools/python_keywords/continue b/python/helpers/tools/python_keywords/continue new file mode 100644 index 000000000000..9f2fbf2403d4 --- /dev/null +++ b/python/helpers/tools/python_keywords/continue @@ -0,0 +1,13 @@ +
+

The continue statement

+
+continue_stmt ::=  "continue"
+
+

continue may only occur syntactically nested in a for or +while loop, but not nested in a function or class definition or +finally clause within that loop. It continues with the next +cycle of the nearest enclosing loop.

+

When continue passes control out of a try statement with a +finally clause, that finally clause is executed before +really starting the next loop cycle.

+
diff --git a/python/helpers/tools/python_keywords/def b/python/helpers/tools/python_keywords/def new file mode 100644 index 000000000000..184983ecce4c --- /dev/null +++ b/python/helpers/tools/python_keywords/def @@ -0,0 +1,102 @@ +
+

Function definitions

+

A function definition defines a user-defined function object (see section +The standard type hierarchy):

+
+funcdef        ::=  [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
+decorators     ::=  decorator+
+decorator      ::=  "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
+dotted_name    ::=  identifier ("." identifier)*
+parameter_list ::=  (defparameter ",")*
+                    | "*" [parameter] ("," defparameter)* ["," "**" parameter]
+                    | "**" parameter
+                    | defparameter [","] )
+parameter      ::=  identifier [":" expression]
+defparameter   ::=  parameter ["=" expression]
+funcname       ::=  identifier
+
+

A function definition is an executable statement. Its execution binds the +function name in the current local namespace to a function object (a wrapper +around the executable code for the function). This function object contains a +reference to the current global namespace as the global namespace to be used +when the function is called.

+

The function definition does not execute the function body; this gets executed +only when the function is called. [3]

+

A function definition may be wrapped by one or more decorator expressions. +Decorator expressions are evaluated when the function is defined, in the scope +that contains the function definition. The result must be a callable, which is +invoked with the function object as the only argument. The returned value is +bound to the function name instead of the function object. Multiple decorators +are applied in nested fashion. For example, the following code

+
@f1(arg)
+@f2
+def func(): pass
+
+
+

is equivalent to

+
def func(): pass
+func = f1(arg)(f2(func))
+
+
+

When one or more parameters have the form parameter = +expression, the function is said to have “default parameter values.” For a +parameter with a default value, the corresponding argument may be +omitted from a call, in which +case the parameter’s default value is substituted. If a parameter has a default +value, all following parameters up until the “*” must also have a default +value — this is a syntactic restriction that is not expressed by the grammar.

+

Default parameter values are evaluated from left to right when the function +definition is executed. This means that the expression is evaluated once, when +the function is defined, and that the same “pre-computed” value is used for each +call. This is especially important to understand when a default parameter is a +mutable object, such as a list or a dictionary: if the function modifies the +object (e.g. by appending an item to a list), the default value is in effect +modified. This is generally not what was intended. A way around this is to use +None as the default, and explicitly test for it in the body of the function, +e.g.:

+
def whats_on_the_telly(penguin=None):
+    if penguin is None:
+        penguin = []
+    penguin.append("property of the zoo")
+    return penguin
+
+
+

Function call semantics are described in more detail in section Calls. A +function call always assigns values to all parameters mentioned in the parameter +list, either from position arguments, from keyword arguments, or from default +values. If the form “*identifier” is present, it is initialized to a tuple +receiving any excess positional parameters, defaulting to the empty tuple. If +the form “**identifier” is present, it is initialized to a new dictionary +receiving any excess keyword arguments, defaulting to a new empty dictionary. +Parameters after “*” or “*identifier” are keyword-only parameters and +may only be passed used keyword arguments.

+

Parameters may have annotations of the form “: expression” following the +parameter name. Any parameter may have an annotation even those of the form +*identifier or **identifier. Functions may have “return” annotation of +the form “-> expression” after the parameter list. These annotations can be +any valid Python expression and are evaluated when the function definition is +executed. Annotations may be evaluated in a different order than they appear in +the source code. The presence of annotations does not change the semantics of a +function. The annotation values are available as values of a dictionary keyed +by the parameters’ names in the __annotations__ attribute of the +function object.

+

It is also possible to create anonymous functions (functions not bound to a +name), for immediate use in expressions. This uses lambda expressions, described in +section Lambdas. Note that the lambda expression is merely a shorthand for a +simplified function definition; a function defined in a “def” +statement can be passed around or assigned to another name just like a function +defined by a lambda expression. The “def” form is actually more powerful +since it allows the execution of multiple statements and annotations.

+

Programmer’s note: Functions are first-class objects. A “def” statement +executed inside a function definition defines a local function that can be +returned or passed around. Free variables used in the nested function can +access the local variables of the function containing the def. See section +Naming and binding for details.

+
+

See also

+
+
PEP 3107 - Function Annotations
+
The original specification for function annotations.
+
+
+
diff --git a/python/helpers/tools/python_keywords/del b/python/helpers/tools/python_keywords/del new file mode 100644 index 000000000000..57931a7ec033 --- /dev/null +++ b/python/helpers/tools/python_keywords/del @@ -0,0 +1,21 @@ +
+

The del statement

+
+del_stmt ::=  "del" target_list
+
+

Deletion is recursively defined very similar to the way assignment is defined. +Rather than spelling it out in full details, here are some hints.

+

Deletion of a target list recursively deletes each target, from left to right.

+

Deletion of a name removes the binding of that name from the local or global +namespace, depending on whether the name occurs in a global statement +in the same code block. If the name is unbound, a NameError exception +will be raised.

+

Deletion of attribute references, subscriptions and slicings is passed to the +primary object involved; deletion of a slicing is in general equivalent to +assignment of an empty slice of the right type (but even this is determined by +the sliced object).

+
+

Changed in version 3.2: Previously it was illegal to delete a name from the local namespace if it +occurs as a free variable in a nested block.

+
+
diff --git a/python/helpers/tools/python_keywords/elif b/python/helpers/tools/python_keywords/elif new file mode 100644 index 000000000000..399a83e8af27 --- /dev/null +++ b/python/helpers/tools/python_keywords/elif @@ -0,0 +1,14 @@ +
+

The if statement

+

The if statement is used for conditional execution:

+
+if_stmt ::=  "if" expression ":" suite
+             ( "elif" expression ":" suite )*
+             ["else" ":" suite]
+
+

It selects exactly one of the suites by evaluating the expressions one by one +until one is found to be true (see section Boolean operations for the definition of +true and false); then that suite is executed (and no other part of the +if statement is executed or evaluated). If all expressions are +false, the suite of the else clause, if present, is executed.

+
diff --git a/python/helpers/tools/python_keywords/else b/python/helpers/tools/python_keywords/else new file mode 100644 index 000000000000..399a83e8af27 --- /dev/null +++ b/python/helpers/tools/python_keywords/else @@ -0,0 +1,14 @@ +
+

The if statement

+

The if statement is used for conditional execution:

+
+if_stmt ::=  "if" expression ":" suite
+             ( "elif" expression ":" suite )*
+             ["else" ":" suite]
+
+

It selects exactly one of the suites by evaluating the expressions one by one +until one is found to be true (see section Boolean operations for the definition of +true and false); then that suite is executed (and no other part of the +if statement is executed or evaluated). If all expressions are +false, the suite of the else clause, if present, is executed.

+
diff --git a/python/helpers/tools/python_keywords/except b/python/helpers/tools/python_keywords/except new file mode 100644 index 000000000000..72325061ec96 --- /dev/null +++ b/python/helpers/tools/python_keywords/except @@ -0,0 +1,109 @@ +
+

The try statement

+

The try statement specifies exception handlers and/or cleanup code +for a group of statements:

+
+try_stmt  ::=  try1_stmt | try2_stmt
+try1_stmt ::=  "try" ":" suite
+               ("except" [expression ["as" identifier]] ":" suite)+
+               ["else" ":" suite]
+               ["finally" ":" suite]
+try2_stmt ::=  "try" ":" suite
+               "finally" ":" suite
+
+

The except clause(s) specify one or more exception handlers. When no +exception occurs in the try clause, no exception handler is executed. +When an exception occurs in the try suite, a search for an exception +handler is started. This search inspects the except clauses in turn until one +is found that matches the exception. An expression-less except clause, if +present, must be last; it matches any exception. For an except clause with an +expression, that expression is evaluated, and the clause matches the exception +if the resulting object is “compatible” with the exception. An object is +compatible with an exception if it is the class or a base class of the exception +object or a tuple containing an item compatible with the exception.

+

If no except clause matches the exception, the search for an exception handler +continues in the surrounding code and on the invocation stack. [1]

+

If the evaluation of an expression in the header of an except clause raises an +exception, the original search for a handler is canceled and a search starts for +the new exception in the surrounding code and on the call stack (it is treated +as if the entire try statement raised the exception).

+

When a matching except clause is found, the exception is assigned to the target +specified after the as keyword in that except clause, if present, and +the except clause’s suite is executed. All except clauses must have an +executable block. When the end of this block is reached, execution continues +normally after the entire try statement. (This means that if two nested +handlers exist for the same exception, and the exception occurs in the try +clause of the inner handler, the outer handler will not handle the exception.)

+

When an exception has been assigned using as target, it is cleared at the +end of the except clause. This is as if

+
except E as N:
+    foo
+
+
+

was translated to

+
except E as N:
+    try:
+        foo
+    finally:
+        del N
+
+
+

This means the exception must be assigned to a different name to be able to +refer to it after the except clause. Exceptions are cleared because with the +traceback attached to them, they form a reference cycle with the stack frame, +keeping all locals in that frame alive until the next garbage collection occurs.

+

Before an except clause’s suite is executed, details about the exception are +stored in the sys module and can be accessed via sys.exc_info(). +sys.exc_info() returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section The standard type hierarchy) identifying +the point in the program where the exception occurred. sys.exc_info() +values are restored to their previous values (before the call) when returning +from a function that handled an exception.

+

The optional else clause is executed if and when control flows off +the end of the try clause. [2] Exceptions in the else +clause are not handled by the preceding except clauses.

+

If finally is present, it specifies a ‘cleanup’ handler. The +try clause is executed, including any except and +else clauses. If an exception occurs in any of the clauses and is +not handled, the exception is temporarily saved. The finally clause +is executed. If there is a saved exception it is re-raised at the end of the +finally clause. If the finally clause raises another +exception, the saved exception is set as the context of the new exception. +If the finally clause executes a return or break +statement, the saved exception is discarded:

+
>>> def f():
+...     try:
+...         1/0
+...     finally:
+...         return 42
+...
+>>> f()
+42
+
+
+

The exception information is not available to the program during execution of +the finally clause.

+

When a return, break or continue statement is +executed in the try suite of a try...finally +statement, the finally clause is also executed ‘on the way out.’ A +continue statement is illegal in the finally clause. (The +reason is a problem with the current implementation — this restriction may be +lifted in the future).

+

The return value of a function is determined by the last return +statement executed. Since the finally clause always executes, a +return statement executed in the finally clause will +always be the last one executed:

+
>>> def foo():
+...     try:
+...         return 'try'
+...     finally:
+...         return 'finally'
+...
+>>> foo()
+'finally'
+
+
+

Additional information on exceptions can be found in section Exceptions, +and information on using the raise statement to generate exceptions +may be found in section The raise statement.

+
diff --git a/python/helpers/tools/python_keywords/exec b/python/helpers/tools/python_keywords/exec new file mode 100644 index 000000000000..f6d8ea6a0e9f --- /dev/null +++ b/python/helpers/tools/python_keywords/exec @@ -0,0 +1,43 @@ +
+

The exec statement

+
+exec_stmt ::=  "exec" or_expr ["in" expression ["," expression]]
+
+

This statement supports dynamic execution of Python code. The first expression +should evaluate to either a string, an open file object, or a code object. If +it is a string, the string is parsed as a suite of Python statements which is +then executed (unless a syntax error occurs). [1] If it is an open file, the file +is parsed until EOF and executed. If it is a code object, it is simply +executed. In all cases, the code that’s executed is expected to be valid as +file input (see section File input). Be aware that the +return and yield statements may not be used outside of +function definitions even within the context of code passed to the +exec statement.

+

In all cases, if the optional parts are omitted, the code is executed in the +current scope. If only the first expression after in is specified, +it should be a dictionary, which will be used for both the global and the local +variables. If two expressions are given, they are used for the global and local +variables, respectively. If provided, locals can be any mapping object.

+

+Changed in version 2.4: Formerly, locals was required to be a dictionary.

+

As a side effect, an implementation may insert additional keys into the +dictionaries given besides those corresponding to variable names set by the +executed code. For example, the current implementation may add a reference to +the dictionary of the built-in module __builtin__ under the key +__builtins__ (!).

+

Programmer’s hints: dynamic evaluation of expressions is supported by the +built-in function eval(). The built-in functions globals() and +locals() return the current global and local dictionary, respectively, +which may be useful to pass around for use by exec.

+

Footnotes

+ + + + + +
[1]Note that the parser only accepts the Unix-style end of line convention. +If you are reading the code from a file, make sure to use universal +newline mode to convert Windows or Mac-style newlines.
+
+ + diff --git a/python/helpers/tools/python_keywords/finally b/python/helpers/tools/python_keywords/finally new file mode 100644 index 000000000000..72325061ec96 --- /dev/null +++ b/python/helpers/tools/python_keywords/finally @@ -0,0 +1,109 @@ +
+

The try statement

+

The try statement specifies exception handlers and/or cleanup code +for a group of statements:

+
+try_stmt  ::=  try1_stmt | try2_stmt
+try1_stmt ::=  "try" ":" suite
+               ("except" [expression ["as" identifier]] ":" suite)+
+               ["else" ":" suite]
+               ["finally" ":" suite]
+try2_stmt ::=  "try" ":" suite
+               "finally" ":" suite
+
+

The except clause(s) specify one or more exception handlers. When no +exception occurs in the try clause, no exception handler is executed. +When an exception occurs in the try suite, a search for an exception +handler is started. This search inspects the except clauses in turn until one +is found that matches the exception. An expression-less except clause, if +present, must be last; it matches any exception. For an except clause with an +expression, that expression is evaluated, and the clause matches the exception +if the resulting object is “compatible” with the exception. An object is +compatible with an exception if it is the class or a base class of the exception +object or a tuple containing an item compatible with the exception.

+

If no except clause matches the exception, the search for an exception handler +continues in the surrounding code and on the invocation stack. [1]

+

If the evaluation of an expression in the header of an except clause raises an +exception, the original search for a handler is canceled and a search starts for +the new exception in the surrounding code and on the call stack (it is treated +as if the entire try statement raised the exception).

+

When a matching except clause is found, the exception is assigned to the target +specified after the as keyword in that except clause, if present, and +the except clause’s suite is executed. All except clauses must have an +executable block. When the end of this block is reached, execution continues +normally after the entire try statement. (This means that if two nested +handlers exist for the same exception, and the exception occurs in the try +clause of the inner handler, the outer handler will not handle the exception.)

+

When an exception has been assigned using as target, it is cleared at the +end of the except clause. This is as if

+
except E as N:
+    foo
+
+
+

was translated to

+
except E as N:
+    try:
+        foo
+    finally:
+        del N
+
+
+

This means the exception must be assigned to a different name to be able to +refer to it after the except clause. Exceptions are cleared because with the +traceback attached to them, they form a reference cycle with the stack frame, +keeping all locals in that frame alive until the next garbage collection occurs.

+

Before an except clause’s suite is executed, details about the exception are +stored in the sys module and can be accessed via sys.exc_info(). +sys.exc_info() returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section The standard type hierarchy) identifying +the point in the program where the exception occurred. sys.exc_info() +values are restored to their previous values (before the call) when returning +from a function that handled an exception.

+

The optional else clause is executed if and when control flows off +the end of the try clause. [2] Exceptions in the else +clause are not handled by the preceding except clauses.

+

If finally is present, it specifies a ‘cleanup’ handler. The +try clause is executed, including any except and +else clauses. If an exception occurs in any of the clauses and is +not handled, the exception is temporarily saved. The finally clause +is executed. If there is a saved exception it is re-raised at the end of the +finally clause. If the finally clause raises another +exception, the saved exception is set as the context of the new exception. +If the finally clause executes a return or break +statement, the saved exception is discarded:

+
>>> def f():
+...     try:
+...         1/0
+...     finally:
+...         return 42
+...
+>>> f()
+42
+
+
+

The exception information is not available to the program during execution of +the finally clause.

+

When a return, break or continue statement is +executed in the try suite of a try...finally +statement, the finally clause is also executed ‘on the way out.’ A +continue statement is illegal in the finally clause. (The +reason is a problem with the current implementation — this restriction may be +lifted in the future).

+

The return value of a function is determined by the last return +statement executed. Since the finally clause always executes, a +return statement executed in the finally clause will +always be the last one executed:

+
>>> def foo():
+...     try:
+...         return 'try'
+...     finally:
+...         return 'finally'
+...
+>>> foo()
+'finally'
+
+
+

Additional information on exceptions can be found in section Exceptions, +and information on using the raise statement to generate exceptions +may be found in section The raise statement.

+
diff --git a/python/helpers/tools/python_keywords/for b/python/helpers/tools/python_keywords/for new file mode 100644 index 000000000000..c060b273ad92 --- /dev/null +++ b/python/helpers/tools/python_keywords/for @@ -0,0 +1,55 @@ +
+

The for statement

+

The for statement is used to iterate over the elements of a sequence +(such as a string, tuple or list) or other iterable object:

+
+for_stmt ::=  "for" target_list "in" expression_list ":" suite
+              ["else" ":" suite]
+
+

The expression list is evaluated once; it should yield an iterable object. An +iterator is created for the result of the expression_list. The suite is +then executed once for each item provided by the iterator, in the order returned +by the iterator. Each item in turn is assigned to the target list using the +standard rules for assignments (see Assignment statements), and then the suite is +executed. When the items are exhausted (which is immediately when the sequence +is empty or an iterator raises a StopIteration exception), the suite in +the else clause, if present, is executed, and the loop terminates.

+

A break statement executed in the first suite terminates the loop +without executing the else clause’s suite. A continue +statement executed in the first suite skips the rest of the suite and continues +with the next item, or with the else clause if there is no next +item.

+

The for-loop makes assignments to the variables(s) in the target list. +This overwrites all previous assignments to those variables including +those made in the suite of the for-loop:

+
for i in range(10):
+    print(i)
+    i = 5             # this will not affect the for-loop
+                      # because i will be overwritten with the next
+                      # index in the range
+
+
+

Names in the target list are not deleted when the loop is finished, but if the +sequence is empty, they will not have been assigned to at all by the loop. Hint: +the built-in function range() returns an iterator of integers suitable to +emulate the effect of Pascal’s for i := a to b do; e.g., list(range(3)) +returns the list [0, 1, 2].

+
+

Note

+

There is a subtlety when the sequence is being modified by the loop (this can +only occur for mutable sequences, i.e. lists). An internal counter is used +to keep track of which item is used next, and this is incremented on each +iteration. When this counter has reached the length of the sequence the loop +terminates. This means that if the suite deletes the current (or a previous) +item from the sequence, the next item will be skipped (since it gets the +index of the current item which has already been treated). Likewise, if the +suite inserts an item in the sequence before the current item, the current +item will be treated again the next time through the loop. This can lead to +nasty bugs that can be avoided by making a temporary copy using a slice of +the whole sequence, e.g.,

+
for x in a[:]:
+    if x < 0: a.remove(x)
+
+
+
+
diff --git a/python/helpers/tools/python_keywords/from b/python/helpers/tools/python_keywords/from new file mode 100644 index 000000000000..4636a318f756 --- /dev/null +++ b/python/helpers/tools/python_keywords/from @@ -0,0 +1,96 @@ +
+

The import statement

+
+import_stmt     ::=  "import" module ["as" name] ( "," module ["as" name] )*
+                     | "from" relative_module "import" identifier ["as" name]
+                     ( "," identifier ["as" name] )*
+                     | "from" relative_module "import" "(" identifier ["as" name]
+                     ( "," identifier ["as" name] )* [","] ")"
+                     | "from" module "import" "*"
+module          ::=  (identifier ".")* identifier
+relative_module ::=  "."* module | "."+
+name            ::=  identifier
+
+

The basic import statement (no from clause) is executed in two +steps:

+
    +
  1. find a module, loading and initializing it if necessary
  2. +
  3. define a name or names in the local namespace for the scope where +the import statement occurs.
  4. +
+

When the statement contains multiple clauses (separated by +commas) the two steps are carried out separately for each clause, just +as though the clauses had been separated out into individiual import +statements.

+

The details of the first step, finding and loading modules are described in +greater detail in the section on the import system, +which also describes the various types of packages and modules that can +be imported, as well as all the hooks that can be used to customize +the import system. Note that failures in this step may indicate either +that the module could not be located, or that an error occurred while +initializing the module, which includes execution of the module’s code.

+

If the requested module is retrieved successfully, it will be made +available in the local namespace in one of three ways:

+ +

The from form uses a slightly more complex process:

+
    +
  1. find the module specified in the from clause, loading and +initializing it if necessary;
  2. +
  3. for each of the identifiers specified in the import clauses:
      +
    1. check if the imported module has an attribute by that name
    2. +
    3. if not, attempt to import a submodule with that name and then +check the imported module again for that attribute
    4. +
    5. if the attribute is not found, ImportError is raised.
    6. +
    7. otherwise, a reference to that value is stored in the local namespace, +using the name in the as clause if it is present, +otherwise using the attribute name
    8. +
    +
  4. +
+

Examples:

+
import foo                 # foo imported and bound locally
+import foo.bar.baz         # foo.bar.baz imported, foo bound locally
+import foo.bar.baz as fbb  # foo.bar.baz imported and bound as fbb
+from foo.bar import baz    # foo.bar.baz imported and bound as baz
+from foo import attr       # foo imported and foo.attr bound as attr
+
+
+

If the list of identifiers is replaced by a star ('*'), all public +names defined in the module are bound in the local namespace for the scope +where the import statement occurs.

+

The public names defined by a module are determined by checking the module’s +namespace for a variable named __all__; if defined, it must be a sequence +of strings which are names defined or imported by that module. The names +given in __all__ are all considered public and are required to exist. If +__all__ is not defined, the set of public names includes all names found +in the module’s namespace which do not begin with an underscore character +('_'). __all__ should contain the entire public API. It is intended +to avoid accidentally exporting items that are not part of the API (such as +library modules which were imported and used within the module).

+

The wild card form of import — from module import * — is only allowed at +the module level. Attempting to use it in class or function definitions will +raise a SyntaxError.

+

When specifying what module to import you do not have to specify the absolute +name of the module. When a module or package is contained within another +package it is possible to make a relative import within the same top package +without having to mention the package name. By using leading dots in the +specified module or package after from you can specify how high to +traverse up the current package hierarchy without specifying exact names. One +leading dot means the current package where the module making the import +exists. Two dots means up one package level. Three dots is up two levels, etc. +So if you execute from . import mod from a module in the pkg package +then you will end up importing pkg.mod. If you execute from ..subpkg2 +import mod from within pkg.subpkg1 you will import pkg.subpkg2.mod. +The specification for relative imports is contained within PEP 328.

+

importlib.import_module() is provided to support applications that +determine dynamically the modules to be loaded.

diff --git a/python/helpers/tools/python_keywords/global b/python/helpers/tools/python_keywords/global new file mode 100644 index 000000000000..1b16892d475c --- /dev/null +++ b/python/helpers/tools/python_keywords/global @@ -0,0 +1,28 @@ +
+

The global statement

+
+global_stmt ::=  "global" identifier ("," identifier)*
+
+

The global statement is a declaration which holds for the entire +current code block. It means that the listed identifiers are to be interpreted +as globals. It would be impossible to assign to a global variable without +global, although free variables may refer to globals without being +declared global.

+

Names listed in a global statement must not be used in the same code +block textually preceding that global statement.

+

Names listed in a global statement must not be defined as formal +parameters or in a for loop control target, class +definition, function definition, or import statement.

+
+

CPython implementation detail: The current implementation does not enforce the two restrictions, but +programs should not abuse this freedom, as future implementations may enforce +them or silently change the meaning of the program.

+
+

Programmer’s note: the global is a directive to the parser. It +applies only to code parsed at the same time as the global statement. +In particular, a global statement contained in a string or code +object supplied to the built-in exec() function does not affect the code +block containing the function call, and code contained in such a string is +unaffected by global statements in the code containing the function +call. The same applies to the eval() and compile() functions.

+
diff --git a/python/helpers/tools/python_keywords/if b/python/helpers/tools/python_keywords/if new file mode 100644 index 000000000000..399a83e8af27 --- /dev/null +++ b/python/helpers/tools/python_keywords/if @@ -0,0 +1,14 @@ +
+

The if statement

+

The if statement is used for conditional execution:

+
+if_stmt ::=  "if" expression ":" suite
+             ( "elif" expression ":" suite )*
+             ["else" ":" suite]
+
+

It selects exactly one of the suites by evaluating the expressions one by one +until one is found to be true (see section Boolean operations for the definition of +true and false); then that suite is executed (and no other part of the +if statement is executed or evaluated). If all expressions are +false, the suite of the else clause, if present, is executed.

+
diff --git a/python/helpers/tools/python_keywords/import b/python/helpers/tools/python_keywords/import new file mode 100644 index 000000000000..4636a318f756 --- /dev/null +++ b/python/helpers/tools/python_keywords/import @@ -0,0 +1,96 @@ +
+

The import statement

+
+import_stmt     ::=  "import" module ["as" name] ( "," module ["as" name] )*
+                     | "from" relative_module "import" identifier ["as" name]
+                     ( "," identifier ["as" name] )*
+                     | "from" relative_module "import" "(" identifier ["as" name]
+                     ( "," identifier ["as" name] )* [","] ")"
+                     | "from" module "import" "*"
+module          ::=  (identifier ".")* identifier
+relative_module ::=  "."* module | "."+
+name            ::=  identifier
+
+

The basic import statement (no from clause) is executed in two +steps:

+
    +
  1. find a module, loading and initializing it if necessary
  2. +
  3. define a name or names in the local namespace for the scope where +the import statement occurs.
  4. +
+

When the statement contains multiple clauses (separated by +commas) the two steps are carried out separately for each clause, just +as though the clauses had been separated out into individiual import +statements.

+

The details of the first step, finding and loading modules are described in +greater detail in the section on the import system, +which also describes the various types of packages and modules that can +be imported, as well as all the hooks that can be used to customize +the import system. Note that failures in this step may indicate either +that the module could not be located, or that an error occurred while +initializing the module, which includes execution of the module’s code.

+

If the requested module is retrieved successfully, it will be made +available in the local namespace in one of three ways:

+
    +
  • If the module name is followed by as, then the name +following as is bound directly to the imported module.
  • +
  • If no other name is specified, and the module being imported is a top +level module, the module’s name is bound in the local namespace as a +reference to the imported module
  • +
  • If the module being imported is not a top level module, then the name +of the top level package that contains the module is bound in the local +namespace as a reference to the top level package. The imported module +must be accessed using its full qualified name rather than directly
  • +
+

The from form uses a slightly more complex process:

+
    +
  1. find the module specified in the from clause, loading and +initializing it if necessary;
  2. +
  3. for each of the identifiers specified in the import clauses:
      +
    1. check if the imported module has an attribute by that name
    2. +
    3. if not, attempt to import a submodule with that name and then +check the imported module again for that attribute
    4. +
    5. if the attribute is not found, ImportError is raised.
    6. +
    7. otherwise, a reference to that value is stored in the local namespace, +using the name in the as clause if it is present, +otherwise using the attribute name
    8. +
    +
  4. +
+

Examples:

+
import foo                 # foo imported and bound locally
+import foo.bar.baz         # foo.bar.baz imported, foo bound locally
+import foo.bar.baz as fbb  # foo.bar.baz imported and bound as fbb
+from foo.bar import baz    # foo.bar.baz imported and bound as baz
+from foo import attr       # foo imported and foo.attr bound as attr
+
+
+

If the list of identifiers is replaced by a star ('*'), all public +names defined in the module are bound in the local namespace for the scope +where the import statement occurs.

+

The public names defined by a module are determined by checking the module’s +namespace for a variable named __all__; if defined, it must be a sequence +of strings which are names defined or imported by that module. The names +given in __all__ are all considered public and are required to exist. If +__all__ is not defined, the set of public names includes all names found +in the module’s namespace which do not begin with an underscore character +('_'). __all__ should contain the entire public API. It is intended +to avoid accidentally exporting items that are not part of the API (such as +library modules which were imported and used within the module).

+

The wild card form of import — from module import * — is only allowed at +the module level. Attempting to use it in class or function definitions will +raise a SyntaxError.

+

When specifying what module to import you do not have to specify the absolute +name of the module. When a module or package is contained within another +package it is possible to make a relative import within the same top package +without having to mention the package name. By using leading dots in the +specified module or package after from you can specify how high to +traverse up the current package hierarchy without specifying exact names. One +leading dot means the current package where the module making the import +exists. Two dots means up one package level. Three dots is up two levels, etc. +So if you execute from . import mod from a module in the pkg package +then you will end up importing pkg.mod. If you execute from ..subpkg2 +import mod from within pkg.subpkg1 you will import pkg.subpkg2.mod. +The specification for relative imports is contained within PEP 328.

+

importlib.import_module() is provided to support applications that +determine dynamically the modules to be loaded.

diff --git a/python/helpers/tools/python_keywords/in b/python/helpers/tools/python_keywords/in new file mode 100644 index 000000000000..e07b49ebc138 --- /dev/null +++ b/python/helpers/tools/python_keywords/in @@ -0,0 +1,97 @@ +
+

Comparisons

+

Unlike C, all comparison operations in Python have the same priority, which is +lower than that of any arithmetic, shifting or bitwise operation. Also unlike +C, expressions like a < b < c have the interpretation that is conventional +in mathematics:

+
+comparison    ::=  or_expr ( comp_operator or_expr )*
+comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "<>" | "!="
+                   | "is" ["not"] | ["not"] "in"
+
+

Comparisons yield boolean values: True or False.

+

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to +x < y and y <= z, except that y is evaluated only once (but in both +cases z is not evaluated at all when x < y is found to be false).

+

Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., +opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent +to a op1 b and b op2 c and ... y opN z, except that each expression is +evaluated at most once.

+

Note that a op1 b op2 c doesn’t imply any kind of comparison between a and +c, so that, e.g., x < y > z is perfectly legal (though perhaps not +pretty).

+

The forms <> and != are equivalent; for consistency with C, != is +preferred; where != is mentioned below <> is also accepted. The <> +spelling is considered obsolescent.

+

The operators <, >, ==, >=, <=, and != compare the +values of two objects. The objects need not have the same type. If both are +numbers, they are converted to a common type. Otherwise, objects of different +types always compare unequal, and are ordered consistently but arbitrarily. +You can control comparison behavior of objects of non-built-in types by defining +a __cmp__ method or rich comparison methods like __gt__, described in +section Special method names.

+

(This unusual definition of comparison was used to simplify the definition of +operations like sorting and the in and not in operators. +In the future, the comparison rules for objects of different types are likely to +change.)

+

Comparison of objects of the same type depends on the type:

+
    +
  • Numbers are compared arithmetically.

    +
  • +
  • Strings are compared lexicographically using the numeric equivalents (the +result of the built-in function ord()) of their characters. Unicode and +8-bit strings are fully interoperable in this behavior. [4]

    +
  • +
  • Tuples and lists are compared lexicographically using comparison of +corresponding elements. This means that to compare equal, each element must +compare equal and the two sequences must be of the same type and have the same +length.

    +

    If not equal, the sequences are ordered the same as their first differing +elements. For example, cmp([1,2,x], [1,2,y]) returns the same as +cmp(x,y). If the corresponding element does not exist, the shorter sequence +is ordered first (for example, [1,2] < [1,2,3]).

    +
  • +
  • Mappings (dictionaries) compare equal if and only if their sorted (key, value) +lists compare equal. [5] Outcomes other than equality are resolved +consistently, but are not otherwise defined. [6]

    +
  • +
  • Most other objects of built-in types compare unequal unless they are the same +object; the choice whether one object is considered smaller or larger than +another one is made arbitrarily but consistently within one execution of a +program.

    +
  • +
+

The operators in and not in test for collection +membership. x in s evaluates to true if x is a member of the collection +s, and false otherwise. x not in s returns the negation of x in s. +The collection membership test has traditionally been bound to sequences; an +object is a member of a collection if the collection is a sequence and contains +an element equal to that object. However, it make sense for many other object +types to support membership tests without being a sequence. In particular, +dictionaries (for keys) and sets support membership testing.

+

For the list and tuple types, x in y is true if and only if there exists an +index i such that x == y[i] is true.

+

For the Unicode and string types, x in y is true if and only if x is a +substring of y. An equivalent test is y.find(x) != -1. Note, x and y +need not be the same type; consequently, u'ab' in 'abc' will return +True. Empty strings are always considered to be a substring of any other +string, so "" in "abc" will return True.

+

+Changed in version 2.3: Previously, x was required to be a string of length 1.

+

For user-defined classes which define the __contains__() method, x in +y is true if and only if y.__contains__(x) is true.

+

For user-defined classes which do not define __contains__() but do define +__iter__(), x in y is true if some value z with x == z is +produced while iterating over y. If an exception is raised during the +iteration, it is as if in raised that exception.

+

Lastly, the old-style iteration protocol is tried: if a class defines +__getitem__(), x in y is true if and only if there is a non-negative +integer index i such that x == y[i], and all lower integer indices do not +raise IndexError exception. (If any other exception is raised, it is as +if in raised that exception).

+

The operator not in is defined to have the inverse true value of +in.

+

The operators is and is not test for object identity: x +is y is true if and only if x and y are the same object. x is not y +yields the inverse truth value. [7]

+
diff --git a/python/helpers/tools/python_keywords/is b/python/helpers/tools/python_keywords/is new file mode 100644 index 000000000000..e07b49ebc138 --- /dev/null +++ b/python/helpers/tools/python_keywords/is @@ -0,0 +1,97 @@ +
+

Comparisons

+

Unlike C, all comparison operations in Python have the same priority, which is +lower than that of any arithmetic, shifting or bitwise operation. Also unlike +C, expressions like a < b < c have the interpretation that is conventional +in mathematics:

+
+comparison    ::=  or_expr ( comp_operator or_expr )*
+comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "<>" | "!="
+                   | "is" ["not"] | ["not"] "in"
+
+

Comparisons yield boolean values: True or False.

+

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to +x < y and y <= z, except that y is evaluated only once (but in both +cases z is not evaluated at all when x < y is found to be false).

+

Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., +opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent +to a op1 b and b op2 c and ... y opN z, except that each expression is +evaluated at most once.

+

Note that a op1 b op2 c doesn’t imply any kind of comparison between a and +c, so that, e.g., x < y > z is perfectly legal (though perhaps not +pretty).

+

The forms <> and != are equivalent; for consistency with C, != is +preferred; where != is mentioned below <> is also accepted. The <> +spelling is considered obsolescent.

+

The operators <, >, ==, >=, <=, and != compare the +values of two objects. The objects need not have the same type. If both are +numbers, they are converted to a common type. Otherwise, objects of different +types always compare unequal, and are ordered consistently but arbitrarily. +You can control comparison behavior of objects of non-built-in types by defining +a __cmp__ method or rich comparison methods like __gt__, described in +section Special method names.

+

(This unusual definition of comparison was used to simplify the definition of +operations like sorting and the in and not in operators. +In the future, the comparison rules for objects of different types are likely to +change.)

+

Comparison of objects of the same type depends on the type:

+
    +
  • Numbers are compared arithmetically.

    +
  • +
  • Strings are compared lexicographically using the numeric equivalents (the +result of the built-in function ord()) of their characters. Unicode and +8-bit strings are fully interoperable in this behavior. [4]

    +
  • +
  • Tuples and lists are compared lexicographically using comparison of +corresponding elements. This means that to compare equal, each element must +compare equal and the two sequences must be of the same type and have the same +length.

    +

    If not equal, the sequences are ordered the same as their first differing +elements. For example, cmp([1,2,x], [1,2,y]) returns the same as +cmp(x,y). If the corresponding element does not exist, the shorter sequence +is ordered first (for example, [1,2] < [1,2,3]).

    +
  • +
  • Mappings (dictionaries) compare equal if and only if their sorted (key, value) +lists compare equal. [5] Outcomes other than equality are resolved +consistently, but are not otherwise defined. [6]

    +
  • +
  • Most other objects of built-in types compare unequal unless they are the same +object; the choice whether one object is considered smaller or larger than +another one is made arbitrarily but consistently within one execution of a +program.

    +
  • +
+

The operators in and not in test for collection +membership. x in s evaluates to true if x is a member of the collection +s, and false otherwise. x not in s returns the negation of x in s. +The collection membership test has traditionally been bound to sequences; an +object is a member of a collection if the collection is a sequence and contains +an element equal to that object. However, it make sense for many other object +types to support membership tests without being a sequence. In particular, +dictionaries (for keys) and sets support membership testing.

+

For the list and tuple types, x in y is true if and only if there exists an +index i such that x == y[i] is true.

+

For the Unicode and string types, x in y is true if and only if x is a +substring of y. An equivalent test is y.find(x) != -1. Note, x and y +need not be the same type; consequently, u'ab' in 'abc' will return +True. Empty strings are always considered to be a substring of any other +string, so "" in "abc" will return True.

+

+Changed in version 2.3: Previously, x was required to be a string of length 1.

+

For user-defined classes which define the __contains__() method, x in +y is true if and only if y.__contains__(x) is true.

+

For user-defined classes which do not define __contains__() but do define +__iter__(), x in y is true if some value z with x == z is +produced while iterating over y. If an exception is raised during the +iteration, it is as if in raised that exception.

+

Lastly, the old-style iteration protocol is tried: if a class defines +__getitem__(), x in y is true if and only if there is a non-negative +integer index i such that x == y[i], and all lower integer indices do not +raise IndexError exception. (If any other exception is raised, it is as +if in raised that exception).

+

The operator not in is defined to have the inverse true value of +in.

+

The operators is and is not test for object identity: x +is y is true if and only if x and y are the same object. x is not y +yields the inverse truth value. [7]

+
diff --git a/python/helpers/tools/python_keywords/lambda b/python/helpers/tools/python_keywords/lambda new file mode 100644 index 000000000000..a2c91d353a3a --- /dev/null +++ b/python/helpers/tools/python_keywords/lambda @@ -0,0 +1,17 @@ +
+

Lambdas

+
+lambda_expr        ::=  "lambda" [parameter_list]: expression
+lambda_expr_nocond ::=  "lambda" [parameter_list]: expression_nocond
+
+

Lambda expressions (sometimes called lambda forms) are used to create anonymous +functions. The expression lambda arguments: expression yields a function +object. The unnamed object behaves like a function object defined with

+
def <lambda>(arguments):
+    return expression
+
+
+

See section Function definitions for the syntax of parameter lists. Note that +functions created with lambda expressions cannot contain statements or +annotations.

+
diff --git a/python/helpers/tools/python_keywords/nonlocal b/python/helpers/tools/python_keywords/nonlocal new file mode 100644 index 000000000000..d5c0287e8b6a --- /dev/null +++ b/python/helpers/tools/python_keywords/nonlocal @@ -0,0 +1,25 @@ +
+

The nonlocal statement

+
+nonlocal_stmt ::=  "nonlocal" identifier ("," identifier)*
+
+

The nonlocal statement causes the listed identifiers to refer to +previously bound variables in the nearest enclosing scope excluding globals. +This is important because the default behavior for binding is to search the +local namespace first. The statement allows encapsulated code to rebind +variables outside of the local scope besides the global (module) scope.

+

Names listed in a nonlocal statement, unlike those listed in a +global statement, must refer to pre-existing bindings in an +enclosing scope (the scope in which a new binding should be created cannot +be determined unambiguously).

+

Names listed in a nonlocal statement must not collide with +pre-existing bindings in the local scope.

+
+

See also

+
+
PEP 3104 - Access to Names in Outer Scopes
+
The specification for the nonlocal statement.
+
+
+
+
diff --git a/python/helpers/tools/python_keywords/not b/python/helpers/tools/python_keywords/not new file mode 100644 index 000000000000..9b21ad3ed531 --- /dev/null +++ b/python/helpers/tools/python_keywords/not @@ -0,0 +1,27 @@ +
+

Boolean operations

+
+or_test  ::=  and_test | or_test "or" and_test
+and_test ::=  not_test | and_test "and" not_test
+not_test ::=  comparison | "not" not_test
+
+

In the context of Boolean operations, and also when expressions are used by +control flow statements, the following values are interpreted as false: +False, None, numeric zero of all types, and empty strings and containers +(including strings, tuples, lists, dictionaries, sets and frozensets). All +other values are interpreted as true. User-defined objects can customize their +truth value by providing a __bool__() method.

+

The operator not yields True if its argument is false, False +otherwise.

+

The expression x and y first evaluates x; if x is false, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

The expression x or y first evaluates x; if x is true, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

(Note that neither and nor or restrict the value and type +they return to False and True, but rather return the last evaluated +argument. This is sometimes useful, e.g., if s is a string that should be +replaced by a default value if it is empty, the expression s or 'foo' yields +the desired value. Because not has to create a new value, it +returns a boolean value regardless of the type of its argument +(for example, not 'foo' produces False rather than ''.)

+
diff --git a/python/helpers/tools/python_keywords/or b/python/helpers/tools/python_keywords/or new file mode 100644 index 000000000000..9b21ad3ed531 --- /dev/null +++ b/python/helpers/tools/python_keywords/or @@ -0,0 +1,27 @@ +
+

Boolean operations

+
+or_test  ::=  and_test | or_test "or" and_test
+and_test ::=  not_test | and_test "and" not_test
+not_test ::=  comparison | "not" not_test
+
+

In the context of Boolean operations, and also when expressions are used by +control flow statements, the following values are interpreted as false: +False, None, numeric zero of all types, and empty strings and containers +(including strings, tuples, lists, dictionaries, sets and frozensets). All +other values are interpreted as true. User-defined objects can customize their +truth value by providing a __bool__() method.

+

The operator not yields True if its argument is false, False +otherwise.

+

The expression x and y first evaluates x; if x is false, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

The expression x or y first evaluates x; if x is true, its value is +returned; otherwise, y is evaluated and the resulting value is returned.

+

(Note that neither and nor or restrict the value and type +they return to False and True, but rather return the last evaluated +argument. This is sometimes useful, e.g., if s is a string that should be +replaced by a default value if it is empty, the expression s or 'foo' yields +the desired value. Because not has to create a new value, it +returns a boolean value regardless of the type of its argument +(for example, not 'foo' produces False rather than ''.)

+
diff --git a/python/helpers/tools/python_keywords/pass b/python/helpers/tools/python_keywords/pass new file mode 100644 index 000000000000..db33f8df7dfd --- /dev/null +++ b/python/helpers/tools/python_keywords/pass @@ -0,0 +1,14 @@ +
+

The pass statement

+
+pass_stmt ::=  "pass"
+
+

pass is a null operation — when it is executed, nothing happens. +It is useful as a placeholder when a statement is required syntactically, but no +code needs to be executed, for example:

+
def f(arg): pass    # a function that does nothing (yet)
+
+class C: pass       # a class with no methods (yet)
+
+
+
diff --git a/python/helpers/tools/python_keywords/raise b/python/helpers/tools/python_keywords/raise new file mode 100644 index 000000000000..e7d729141d40 --- /dev/null +++ b/python/helpers/tools/python_keywords/raise @@ -0,0 +1,66 @@ +
+

The raise statement

+
+raise_stmt ::=  "raise" [expression ["from" expression]]
+
+

If no expressions are present, raise re-raises the last exception +that was active in the current scope. If no exception is active in the current +scope, a RuntimeError exception is raised indicating that this is an +error.

+

Otherwise, raise evaluates the first expression as the exception +object. It must be either a subclass or an instance of BaseException. +If it is a class, the exception instance will be obtained when needed by +instantiating the class with no arguments.

+

The type of the exception is the exception instance’s class, the +value is the instance itself.

+

A traceback object is normally created automatically when an exception is raised +and attached to it as the __traceback__ attribute, which is writable. +You can create an exception and set your own traceback in one step using the +with_traceback() exception method (which returns the same exception +instance, with its traceback set to its argument), like so:

+
raise Exception("foo occurred").with_traceback(tracebackobj)
+
+
+

The from clause is used for exception chaining: if given, the second +expression must be another exception class or instance, which will then be +attached to the raised exception as the __cause__ attribute (which is +writable). If the raised exception is not handled, both exceptions will be +printed:

+
>>> try:
+...     print(1 / 0)
+... except Exception as exc:
+...     raise RuntimeError("Something bad happened") from exc
+...
+Traceback (most recent call last):
+  File "<stdin>", line 2, in <module>
+ZeroDivisionError: int division or modulo by zero
+
+The above exception was the direct cause of the following exception:
+
+Traceback (most recent call last):
+  File "<stdin>", line 4, in <module>
+RuntimeError: Something bad happened
+
+
+

A similar mechanism works implicitly if an exception is raised inside an +exception handler or a finally clause: the previous exception is then +attached as the new exception’s __context__ attribute:

+
>>> try:
+...     print(1 / 0)
+... except:
+...     raise RuntimeError("Something bad happened")
+...
+Traceback (most recent call last):
+  File "<stdin>", line 2, in <module>
+ZeroDivisionError: int division or modulo by zero
+
+During handling of the above exception, another exception occurred:
+
+Traceback (most recent call last):
+  File "<stdin>", line 4, in <module>
+RuntimeError: Something bad happened
+
+
+

Additional information on exceptions can be found in section Exceptions, +and information about handling exceptions is in section The try statement.

+
diff --git a/python/helpers/tools/python_keywords/return b/python/helpers/tools/python_keywords/return new file mode 100644 index 000000000000..42cfb9fc4314 --- /dev/null +++ b/python/helpers/tools/python_keywords/return @@ -0,0 +1,18 @@ +
+

The return statement

+
+return_stmt ::=  "return" [expression_list]
+
+

return may only occur syntactically nested in a function definition, +not within a nested class definition.

+

If an expression list is present, it is evaluated, else None is substituted.

+

return leaves the current function call with the expression list (or +None) as return value.

+

When return passes control out of a try statement with a +finally clause, that finally clause is executed before +really leaving the function.

+

In a generator function, the return statement indicates that the +generator is done and will cause StopIteration to be raised. The returned +value (if any) is used as an argument to construct StopIteration and +becomes the StopIteration.value attribute.

+
\ No newline at end of file diff --git a/python/helpers/tools/python_keywords/try b/python/helpers/tools/python_keywords/try new file mode 100644 index 000000000000..72325061ec96 --- /dev/null +++ b/python/helpers/tools/python_keywords/try @@ -0,0 +1,109 @@ +
+

The try statement

+

The try statement specifies exception handlers and/or cleanup code +for a group of statements:

+
+try_stmt  ::=  try1_stmt | try2_stmt
+try1_stmt ::=  "try" ":" suite
+               ("except" [expression ["as" identifier]] ":" suite)+
+               ["else" ":" suite]
+               ["finally" ":" suite]
+try2_stmt ::=  "try" ":" suite
+               "finally" ":" suite
+
+

The except clause(s) specify one or more exception handlers. When no +exception occurs in the try clause, no exception handler is executed. +When an exception occurs in the try suite, a search for an exception +handler is started. This search inspects the except clauses in turn until one +is found that matches the exception. An expression-less except clause, if +present, must be last; it matches any exception. For an except clause with an +expression, that expression is evaluated, and the clause matches the exception +if the resulting object is “compatible” with the exception. An object is +compatible with an exception if it is the class or a base class of the exception +object or a tuple containing an item compatible with the exception.

+

If no except clause matches the exception, the search for an exception handler +continues in the surrounding code and on the invocation stack. [1]

+

If the evaluation of an expression in the header of an except clause raises an +exception, the original search for a handler is canceled and a search starts for +the new exception in the surrounding code and on the call stack (it is treated +as if the entire try statement raised the exception).

+

When a matching except clause is found, the exception is assigned to the target +specified after the as keyword in that except clause, if present, and +the except clause’s suite is executed. All except clauses must have an +executable block. When the end of this block is reached, execution continues +normally after the entire try statement. (This means that if two nested +handlers exist for the same exception, and the exception occurs in the try +clause of the inner handler, the outer handler will not handle the exception.)

+

When an exception has been assigned using as target, it is cleared at the +end of the except clause. This is as if

+
except E as N:
+    foo
+
+
+

was translated to

+
except E as N:
+    try:
+        foo
+    finally:
+        del N
+
+
+

This means the exception must be assigned to a different name to be able to +refer to it after the except clause. Exceptions are cleared because with the +traceback attached to them, they form a reference cycle with the stack frame, +keeping all locals in that frame alive until the next garbage collection occurs.

+

Before an except clause’s suite is executed, details about the exception are +stored in the sys module and can be accessed via sys.exc_info(). +sys.exc_info() returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section The standard type hierarchy) identifying +the point in the program where the exception occurred. sys.exc_info() +values are restored to their previous values (before the call) when returning +from a function that handled an exception.

+

The optional else clause is executed if and when control flows off +the end of the try clause. [2] Exceptions in the else +clause are not handled by the preceding except clauses.

+

If finally is present, it specifies a ‘cleanup’ handler. The +try clause is executed, including any except and +else clauses. If an exception occurs in any of the clauses and is +not handled, the exception is temporarily saved. The finally clause +is executed. If there is a saved exception it is re-raised at the end of the +finally clause. If the finally clause raises another +exception, the saved exception is set as the context of the new exception. +If the finally clause executes a return or break +statement, the saved exception is discarded:

+
>>> def f():
+...     try:
+...         1/0
+...     finally:
+...         return 42
+...
+>>> f()
+42
+
+
+

The exception information is not available to the program during execution of +the finally clause.

+

When a return, break or continue statement is +executed in the try suite of a try...finally +statement, the finally clause is also executed ‘on the way out.’ A +continue statement is illegal in the finally clause. (The +reason is a problem with the current implementation — this restriction may be +lifted in the future).

+

The return value of a function is determined by the last return +statement executed. Since the finally clause always executes, a +return statement executed in the finally clause will +always be the last one executed:

+
>>> def foo():
+...     try:
+...         return 'try'
+...     finally:
+...         return 'finally'
+...
+>>> foo()
+'finally'
+
+
+

Additional information on exceptions can be found in section Exceptions, +and information on using the raise statement to generate exceptions +may be found in section The raise statement.

+
diff --git a/python/helpers/tools/python_keywords/while b/python/helpers/tools/python_keywords/while new file mode 100644 index 000000000000..60de08abd512 --- /dev/null +++ b/python/helpers/tools/python_keywords/while @@ -0,0 +1,17 @@ +
+

The while statement

+

The while statement is used for repeated execution as long as an +expression is true:

+
+while_stmt ::=  "while" expression ":" suite
+                ["else" ":" suite]
+
+

This repeatedly tests the expression and, if it is true, executes the first +suite; if the expression is false (which may be the first time it is tested) the +suite of the else clause, if present, is executed and the loop +terminates.

+

A break statement executed in the first suite terminates the loop +without executing the else clause’s suite. A continue +statement executed in the first suite skips the rest of the suite and goes back +to testing the expression.

+
diff --git a/python/helpers/tools/python_keywords/with b/python/helpers/tools/python_keywords/with new file mode 100644 index 000000000000..5dd4ae70055b --- /dev/null +++ b/python/helpers/tools/python_keywords/with @@ -0,0 +1,69 @@ +
+

The with statement

+

The with statement is used to wrap the execution of a block with +methods defined by a context manager (see section With Statement Context Managers). +This allows common try...except...finally +usage patterns to be encapsulated for convenient reuse.

+
+with_stmt ::=  "with" with_item ("," with_item)* ":" suite
+with_item ::=  expression ["as" target]
+
+

The execution of the with statement with one “item” proceeds as follows:

+
    +
  1. The context expression (the expression given in the with_item) is +evaluated to obtain a context manager.

    +
  2. +
  3. The context manager’s __exit__() is loaded for later use.

    +
  4. +
  5. The context manager’s __enter__() method is invoked.

    +
  6. +
  7. If a target was included in the with statement, the return value +from __enter__() is assigned to it.

    +
    +

    Note

    +

    The with statement guarantees that if the __enter__() +method returns without an error, then __exit__() will always be +called. Thus, if an error occurs during the assignment to the target list, +it will be treated the same as an error occurring within the suite would +be. See step 6 below.

    +
    +
  8. +
  9. The suite is executed.

    +
  10. +
  11. The context manager’s __exit__() method is invoked. If an exception +caused the suite to be exited, its type, value, and traceback are passed as +arguments to __exit__(). Otherwise, three None arguments are +supplied.

    +

    If the suite was exited due to an exception, and the return value from the +__exit__() method was false, the exception is reraised. If the return +value was true, the exception is suppressed, and execution continues with the +statement following the with statement.

    +

    If the suite was exited for any reason other than an exception, the return +value from __exit__() is ignored, and execution proceeds at the normal +location for the kind of exit that was taken.

    +
  12. +
+

With more than one item, the context managers are processed as if multiple +with statements were nested:

+
with A() as a, B() as b:
+    suite
+
+
+

is equivalent to

+
with A() as a:
+    with B() as b:
+        suite
+
+
+
+

Changed in version 3.1: Support for multiple context expressions.

+
+
+

See also

+
+
PEP 0343 - The “with” statement
+
The specification, background, and examples for the Python with +statement.
+
+
+
diff --git a/python/helpers/tools/python_keywords/yield b/python/helpers/tools/python_keywords/yield new file mode 100644 index 000000000000..595a01c9730e --- /dev/null +++ b/python/helpers/tools/python_keywords/yield @@ -0,0 +1,25 @@ +
+

The yield statement

+
+yield_stmt ::=  yield_expression
+
+

A yield statement is semantically equivalent to a yield +expression. The yield statement can be used to omit the parentheses +that would otherwise be required in the equivalent yield expression +statement. For example, the yield statements

+
yield <expr>
+yield from <expr>
+
+
+

are equivalent to the yield expression statements

+
(yield <expr>)
+(yield from <expr>)
+
+
+

Yield expressions and statements are only used when defining a generator +function, and are only used in the body of the generator function. Using yield +in a function definition is sufficient to cause that definition to create a +generator function instead of a normal function.

+

For full details of yield semantics, refer to the +Yield expressions section.

+
diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index bbece4c75b57..ec2fc545ab22 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -19,6 +19,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; @@ -27,9 +28,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; -import com.jetbrains.python.PyBundle; -import com.jetbrains.python.PyNames; -import com.jetbrains.python.PythonFileType; +import com.jetbrains.python.*; import com.jetbrains.python.console.PyConsoleUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; @@ -45,6 +44,9 @@ import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -100,6 +102,11 @@ class PyDocumentationBuilder { myBody.addItem(combUp("\nInferred type: ")); PythonDocumentationProvider.describeExpressionTypeWithLinks(myBody, (PyReferenceExpression)outerElement, context); } + + if (elementDefinition != null && + PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(elementDefinition.getNode().getElementType())) { + buildForKeyword(elementDefinition.getText()); + } if (myBody.isEmpty() && myEpilog.isEmpty()) { return null; // got nothing substantial to say! } @@ -108,6 +115,27 @@ class PyDocumentationBuilder { } } + private void buildForKeyword(@NotNull final String name) { + try { + final FileReader reader = new FileReader(PythonHelpersLocator.getHelperPath("/tools/python_keywords/" + name)); + try { + final String text = FileUtil.loadTextAndClose(reader); + myEpilog.addItem(text); + } + catch (IOException ignored) { + } + finally { + try { + reader.close(); + } + catch (IOException ignored) { + } + } + } + catch (FileNotFoundException ignored) { + } + } + private void buildFromParameter(@NotNull final TypeEvalContext context, @Nullable final PsiElement outerElement, @NotNull final PsiElement elementDefinition) { myBody.addItem(combUp("Parameter " + PyUtil.getReadableRepr(elementDefinition, false))); diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index db42185d968c..bf705cda01d4 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -35,6 +35,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.QualifiedName; import com.intellij.util.Function; import com.jetbrains.python.PyNames; +import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.console.PydevConsoleRunner; import com.jetbrains.python.console.PydevDocumentationProvider; @@ -487,6 +488,18 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i } } + @Nullable + @Override + public PsiElement getCustomDocumentationElement(@NotNull Editor editor, + @NotNull PsiFile file, + @Nullable PsiElement contextElement) { + if (contextElement != null && + PythonDialectsTokenSetProvider.INSTANCE.getKeywordTokens().contains(contextElement.getNode().getElementType())) { + return contextElement; + } + return super.getCustomDocumentationElement(editor, file, contextElement); + } + @Nullable private static PyClass inferContainingClassOf(PsiElement context) { if (context instanceof PyClass) return (PyClass)context; diff --git a/python/testData/quickdoc/ReturnKeyword.html b/python/testData/quickdoc/ReturnKeyword.html new file mode 100644 index 000000000000..038233a4ed2e --- /dev/null +++ b/python/testData/quickdoc/ReturnKeyword.html @@ -0,0 +1,18 @@ +
+

The return statement

+
+return_stmt ::=  "return" [expression_list]
+
+

return may only occur syntactically nested in a function definition, +not within a nested class definition.

+

If an expression list is present, it is evaluated, else None is substituted.

+

return leaves the current function call with the expression list (or +None) as return value.

+

When return passes control out of a try statement with a +finally clause, that finally clause is executed before +really leaving the function.

+

In a generator function, the return statement indicates that the +generator is done and will cause StopIteration to be raised. The returned +value (if any) is used as an argument to construct StopIteration and +becomes the StopIteration.value attribute.

+
\ No newline at end of file diff --git a/python/testData/quickdoc/ReturnKeyword.py b/python/testData/quickdoc/ReturnKeyword.py new file mode 100644 index 000000000000..948ef510825f --- /dev/null +++ b/python/testData/quickdoc/ReturnKeyword.py @@ -0,0 +1,5 @@ +class A(object): + "doc of A" + + def f(self): + return 1 diff --git a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java index e940befd7ef2..add9eb863272 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickDocTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickDocTest.java @@ -233,7 +233,6 @@ public class PyQuickDocTest extends LightMarkedTestCase { checkHover(); } - public void testHoverOverFunction() { checkHover(); } @@ -250,6 +249,12 @@ public class PyQuickDocTest extends LightMarkedTestCase { checkHover(); } + public void testReturnKeyword() { + Map marks = loadTest(); + final PsiElement originalElement = marks.get(""); + checkByHTML(myProvider.generateDoc(originalElement, originalElement)); + } + // PY-13422 public void testNumPyOnesDoc() { myFixture.copyDirectoryToProject("/quickdoc/" + getTestName(false), "");