Provided by: universal-ctags_5.9.20210829.0-1_amd64 bug

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

                             ┌─────┬────────┬──────────┬─────────────────────┐
                             │name │ kind   │ role     │ other    noticeable │
                             │     │        │          │ fields              │
                             ├─────┼────────┼──────────┼─────────────────────┤
                             │X    │ module │ imported │ N/A                 │
                             └─────┴────────┴──────────┴─────────────────────┘

       import X as Y

                       ┌─────┬───────────┬────────────────────┬─────────────────────┐
                       │name │ kind      │ role               │ other    noticeable │
                       │     │           │                    │ fields              │
                       ├─────┼───────────┼────────────────────┼─────────────────────┤
                       │X    │ module    │ indirectlyImported │ N/A                 │
                       ├─────┼───────────┼────────────────────┼─────────────────────┤
                       │Y    │ namespace │ definition         │ nameref:module:X    │
                       └─────┴───────────┴────────────────────┴─────────────────────┘

       from X import *

                             ┌─────┬────────┬───────────┬─────────────────────┐
                             │name │ kind   │ role      │ other    noticeable │
                             │     │        │           │ fields              │
                             ├─────┼────────┼───────────┼─────────────────────┤
                             │X    │ module │ namespace │ N/A                 │
                             └─────┴────────┴───────────┴─────────────────────┘

       from X import Y

                            ┌─────┬─────────┬───────────┬─────────────────────┐
                            │name │ kind    │ role      │ other    noticeable │
                            │     │         │           │ fields              │
                            ├─────┼─────────┼───────────┼─────────────────────┤
                            │X    │ module  │ namespace │ N/A                 │
                            ├─────┼─────────┼───────────┼─────────────────────┤
                            │Y    │ unknown │ imported  │ scope:module:X      │
                            └─────┴─────────┴───────────┴─────────────────────┘

       from X import Y as Z

                        ┌─────┬─────────┬────────────────────┬─────────────────────┐
                        │name │ kind    │ role               │ other    noticeable │
                        │     │         │                    │ fields              │
                        └─────┴─────────┴────────────────────┴─────────────────────┘

                        │X    │ module  │ namespace          │ N/A                 │
                        ├─────┼─────────┼────────────────────┼─────────────────────┤
                        │Y    │ unknown │ indirectlyImported │ scope:module:X      │
                        ├─────┼─────────┼────────────────────┼─────────────────────┤
                        │Z    │ unknown │ definition         │ nameref:unknown:Y   │
                        └─────┴─────────┴────────────────────┴─────────────────────┘

   Examples
       "input.py"

          import X0

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

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

       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"

          import X1 as Y1

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

          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

       "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"

          from X2 import *

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

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

       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"

          from X3 import Y3

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

          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

       "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"

          from X4 import Y4 as Z4

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

          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

       "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

                           ┌─────┬──────────┬────────────┬─────────────────────┐
                           │name │ kind     │ role       │ other    noticeable │
                           │     │          │            │ fields              │
                           ├─────┼──────────┼────────────┼─────────────────────┤
                           │id   │ function │ definition │ signature:(var0)    │
                           └─────┴──────────┴────────────┴─────────────────────┘

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

                  ┌──────────┬──────────┬────────────┬──────────────────────────────────┐
                  │name      │ kind     │ role       │ other    noticeable              │
                  │          │          │            │ fields                           │
                  ├──────────┼──────────┼────────────┼──────────────────────────────────┤
                  │id_t      │ variable │ definition │ typeref:typename:Callable[[int], │
                  │          │          │            │ int]                             │
                  │          │          │            │ nameref:function:anonFuncN       │
                  ├──────────┼──────────┼────────────┼──────────────────────────────────┤
                  │anonFuncN │ function │ definition │ signature:(var1)                 │
                  └──────────┴──────────┴────────────┴──────────────────────────────────┘

   Examples
       "input.py"

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

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

          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)

       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:

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

       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)