Manpages - ctags-lang-python.7

Table of Contents

NAME

ctags-lang-python - Random notes about tagging python source code with Universal Ctags

SYNOPSIS

  ctags ... --languages=+Python ...
  ctags ... --language-force=Python ...
  ctags ... --map-Python=+.py ...

DESCRIPTION

This man page gathers random notes about tagging python source code.

TAGGING IMPORT STATEMENTS

Summary

import X

#+begin_quote

_      
name kind role other noticeable fields
_      
X module imported N/A
_      

#+end_quote

import X as Y

#+begin_quote

_      
name kind role other noticeable fields
_      
X module indirectlyImported N/A
_      
Y namespace definition nameref:module:X
_      

#+end_quote

from X import *

#+begin_quote

_      
name kind role other noticeable fields
_      
X module namespace N/A
_      

#+end_quote

from X import Y

#+begin_quote

_      
name kind role other noticeable fields
_      
X module namespace N/A
_      
Y unknown imported scope:module:/X/
_      

#+end_quote

from X import Y as Z

#+begin_quote

_      
name kind role other noticeable fields
_      
X module namespace N/A
_      
Y unknown indirectlyImported scope:module:/X/
_      
Z unknown definition nameref:unknown:/Y/
_      

#+end_quote

Examples

“input.py”

#+begin_quote

      import X0

#+end_quote

“output.tags” with “–options=NONE -o - –extras=+r –fields=+rzK input.py”

#+begin_quote

      X0      input.py        /^import X0$/;" kind:module     roles:imported

#+end_quote

A tag for an imported module has module kind with imported role. The module is not defined here; it is defined in another file. So the tag for the imported module is a reference tag; specify –extras=+r (or –extras=+{reference}) option for tagging it. “roles:” field enabled with –fields=+r is for recording the module is “imported” to the tag file.

“input.py”

#+begin_quote

      import X1 as Y1

#+end_quote

“output.tags” with “–options=NONE -o - –extras=+r –fields=+rzK –fields-Python=+{nameref} input.py”

#+begin_quote

      X1      input.py        /^import X1 as Y1$/;"   kind:module     roles:indirectlyImported
      Y1      input.py        /^import X1 as Y1$/;"   kind:namespace  roles:def       nameref:module:X1

#+end_quote

“Y1” introduces a new name and is defined here. So “Y1” is tagged as a definition tag. “X1” is imported in a way that its name cannot be used in this source file. For letting client tools know that the name cannot be used, indirectlyImported role is assigned for “X1”. “Y1” is the name for accessing objects defined in the module imported via “X1”. For recording this relationship, nameref: field is attached to the tag of “Y1”. Instead of module kind, namespace kind is assigned to “Y1” because “Y1” itself isn’t a module.

“input.py”

#+begin_quote

      from X2 import *

#+end_quote

“output.tags” with “–options=NONE -o - –extras=+r –fields=+rzK input.py”

#+begin_quote

      X2      input.py        /^from X2 import *$/;"  kind:module     roles:namespace

#+end_quote

The module is not defined here; it is defined in another file. So the tag for the imported module is a reference tag. Unlike “X0” in “import X0”, “X2” may not be used because the names defined in “X2” can be used in this source file. To represent the difference namespace role is attached to “X2” instead of imported.

“input.py”

#+begin_quote

      from X3 import Y3

#+end_quote

“output.tags” with “–options=NONE -o - –extras=+r –fields=+rzKZ input.py”

#+begin_quote

      X3      input.py        /^from X3 import Y3$/;" kind:module     roles:namespace
      Y3      input.py        /^from X3 import Y3$/;" kind:unknown    scope:module:X3 roles:imported

#+end_quote

“Y3” is a name for a language object defined in “X3” module. “scope:module:X3” attached to “Y3” represents this relation between “Y3” and “X3”. ctags assigns unknown kind to “Y3” because ctags cannot know whether “Y3” is a class, a variable, or a function from the input file.

“input.py”

#+begin_quote

      from X4 import Y4 as Z4

#+end_quote

“output.tags” with “–options=NONE -o - –extras=+r –fields=+rzKZ input.py”

#+begin_quote

      X4      input.py        /^from X4 import Y4 as Z4$/;"   kind:module     roles:namespace
      Y4      input.py        /^from X4 import Y4 as Z4$/;"   kind:unknown    scope:module:X4 roles:indirectlyImported
      Z4      input.py        /^from X4 import Y4 as Z4$/;"   kind:unknown    roles:def       nameref:unknown:Y4

#+end_quote

“Y4” is similar to “Y3” of “from X3 import Y3” but the name cannot be used here. indirectlyImported role assigned to “Y4” representing this. “Z4” is the name for accessing the language object named in “Y4” in “X4” module. “nameref:unknown:Y4” attached to “Z4” and “scope:module:X4” attached to “Y4” represent the relations.

LAMBDA EXPRESSION AND TYPE HINT

Summary

id = lambda var0: var0

#+begin_quote

_      
name kind role other noticeable fields
_      
id function definition signature:(var0)
_      

#+end_quote

id_t: Callable[[int], int] = lambda var1: var1

#+begin_quote

_      
name kind role other noticeable fields
_      
id_t variable definition typeref:typename:/Callable[[int], int]/ nameref:function:anonFuncN
_      
anonFuncN function definition signature:(var1)
_      

#+end_quote

Examples

“input.py”

#+begin_quote

      from typing import Callable
      id = lambda var0: var0
      id_t: Callable[[int], int] = lambda var1: var1

#+end_quote

“output.tags” with “–options=NONE -o - –sort=no –fields=+KS –fields-Python=+{nameref} –extras=+{anonymous} input.py”

#+begin_quote

      id      input.py        /^id = lambda var0: var0$/;"    function        signature:(var0)
      id_t    input.py        /^id_t: Callable[[int], int] = lambda var1: var1$/;"\
              variable        typeref:typename:Callable[[int], int]   nameref:function:anonFunc84011d2c0101
      anonFunc84011d2c0101    input.py        /^id_t: Callable[[int], int] = lambda var1: var1$/;"\
              function        signature:(var1)

#+end_quote

If a variable (“id”) with no type hint is initialized with a lambda expression, ctags assigns function kind for the tag of “id”.

If a variable (“id_t”) with a type hint is initialized with a lambda expression, ctags assigns variable kind for the tag of “id_t” with typeref: and nameref: fields. ctags fills typeref: field with the value of the type hint. The way of filling nameref: is a bit complicated.

For the lambda expression used in initializing the type-hint’ed variable, ctags creates anonymous extra tag (“anonFunc84011d2c0101”). ctags fills the nameref: field of “id_t” with the name of anonymous extra tag: “nameref:function:anonFunc84011d2c0101”.

You may think why ctags does so complicated, and why ctags doesn’t emit following tags output for the input:

#+begin_quote

      id      input.py        /^id = \\$/;"   function        signature:(var0)
      id_t    input.py        /^id_t: \\$/;"  function        typeref:typename:Callable[[int], int]   signature:(var1)

#+end_quote

There is a reason. The other languages of ctags obey the following rule: ctags fills typeref: field for a tag of a callable object (like function) with the type of its return value. If we consider “id_t” is a function, its typeref: field should have “typename:int”. However, for filling typeref: with “typename:int”, ctags has to analyze “Callable[[int], int]” deeper. We don’t want to do so.

SEE ALSO

ctags(1), ctags-client-tools(7), ctags-lang-iPythonCell(7)

Author: dt

Created: 2022-02-20 Sun 09:39