noble (7) ctags-universal-lang-python.7.gz

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)