diff mbox series

[v2,14/38] qapi/common.py: Convert comments into docstrings, and elaborate

Message ID 20200922210101.4081073-15-jsnow@redhat.com
State Superseded
Headers show
Series qapi: static typing conversion, pt1 | expand

Commit Message

John Snow Sept. 22, 2020, 9 p.m. UTC
As docstrings, they'll show up in documentation and IDE help.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 scripts/qapi/common.py | 51 ++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 14 deletions(-)

Comments

Eduardo Habkost Sept. 23, 2020, 2:22 p.m. UTC | #1
On Tue, Sep 22, 2020 at 05:00:37PM -0400, John Snow wrote:
> As docstrings, they'll show up in documentation and IDE help.
> 
> Signed-off-by: John Snow <jsnow@redhat.com>

Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Cleber Rosa Sept. 23, 2020, 7:38 p.m. UTC | #2
On Tue, Sep 22, 2020 at 05:00:37PM -0400, John Snow wrote:
> As docstrings, they'll show up in documentation and IDE help.

> 

> Signed-off-by: John Snow <jsnow@redhat.com>

> ---

>  scripts/qapi/common.py | 51 ++++++++++++++++++++++++++++++------------

>  1 file changed, 37 insertions(+), 14 deletions(-)

> 

> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py

> index 0ce4a107e6..730283722a 100644

> --- a/scripts/qapi/common.py

> +++ b/scripts/qapi/common.py

> @@ -20,10 +20,18 @@

>  _C_NAME_TRANS = str.maketrans('.-', '__')

>  

>  

> -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1

> -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2

> -# ENUM24_Name -> ENUM24_NAME

>  def camel_to_upper(value: str) -> str:

> +    """

> +    Converts CamelCase to CAMEL_CASE.

> +

> +    Examples:

> +      ENUMName -> ENUM_NAME

> +      EnumName1 -> ENUM_NAME1

> +      ENUM_NAME -> ENUM_NAME

> +      ENUM_NAME1 -> ENUM_NAME1

> +      ENUM_Name2 -> ENUM_NAME2

> +      ENUM24_Name -> ENUM24_NAME

> +    """

>      c_fun_str = c_name(value, False)

>      if value.isupper():

>          return c_fun_str

> @@ -45,21 +53,33 @@ def camel_to_upper(value: str) -> str:

>  def c_enum_const(type_name: str,

>                   const_name: str,

>                   prefix: Optional[str] = None) -> str:

> +    """

> +    Generate a C enumeration constant name.

> +

> +    :param type_name: The name of the enumeration.

> +    :param const_name: The name of this constant.

> +    :param prefix: Optional, prefix that overrides the type_name.

> +    """

>      if prefix is not None:

>          type_name = prefix

>      return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()

>  

>  

> -# Map @name to a valid C identifier.

> -# If @protect, avoid returning certain ticklish identifiers (like

> -# C keywords) by prepending 'q_'.

> -#

> -# Used for converting 'name' from a 'name':'type' qapi definition

> -# into a generated struct member, as well as converting type names

> -# into substrings of a generated C function name.

> -# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

> -# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

>  def c_name(name: str, protect: bool = True) -> str:

> +    """

> +    Map `name` to a valid C identifier.

> +

> +    Used for converting 'name' from a 'name':'type' qapi definition

> +    into a generated struct member, as well as converting type names

> +    into substrings of a generated C function name.

> +

> +    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

> +    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

> +

> +    :param name: The name to map.

> +    :param protect: If true, avoid returning certain ticklish identifiers

> +                    (like C keywords) by prepending ``q_``.

> +    """

>      # ANSI X3J11/88-090, 3.1.1

>      c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',

>                       'default', 'do', 'double', 'else', 'enum', 'extern',

> @@ -134,9 +154,12 @@ def decrease(self, amount: int = 4) -> int:

>  indent = Indentation()

>  

>  

> -# Generate @code with @kwds interpolated.

> -# Obey indent, and strip EATSPACE.

>  def cgen(code: str, **kwds: object) -> str:

> +    """

> +    Generate `code` with `kwds` interpolated.

> +

> +    Obey `indent`, and strip `EATSPACE`.

> +    """


This probably won't help on IDEs (never checked any), but sphinx will
let you do:

   """
   Generate `code` with `kwds` interpolated.

   Obey `indent`, and strip :data:`EATSPACE`.
   """

I'm not sure that a maximum level of docstring "sphinxzation" is the
goal here, though.

Reviewed-by: Cleber Rosa <crosa@redhat.com>
John Snow Sept. 23, 2020, 9:18 p.m. UTC | #3
On 9/23/20 3:38 PM, Cleber Rosa wrote:
> On Tue, Sep 22, 2020 at 05:00:37PM -0400, John Snow wrote:

>> As docstrings, they'll show up in documentation and IDE help.

>>

>> Signed-off-by: John Snow <jsnow@redhat.com>

>> ---

>>   scripts/qapi/common.py | 51 ++++++++++++++++++++++++++++++------------

>>   1 file changed, 37 insertions(+), 14 deletions(-)

>>

>> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py

>> index 0ce4a107e6..730283722a 100644

>> --- a/scripts/qapi/common.py

>> +++ b/scripts/qapi/common.py

>> @@ -20,10 +20,18 @@

>>   _C_NAME_TRANS = str.maketrans('.-', '__')

>>   

>>   

>> -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1

>> -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2

>> -# ENUM24_Name -> ENUM24_NAME

>>   def camel_to_upper(value: str) -> str:

>> +    """

>> +    Converts CamelCase to CAMEL_CASE.

>> +

>> +    Examples:

>> +      ENUMName -> ENUM_NAME

>> +      EnumName1 -> ENUM_NAME1

>> +      ENUM_NAME -> ENUM_NAME

>> +      ENUM_NAME1 -> ENUM_NAME1

>> +      ENUM_Name2 -> ENUM_NAME2

>> +      ENUM24_Name -> ENUM24_NAME

>> +    """

>>       c_fun_str = c_name(value, False)

>>       if value.isupper():

>>           return c_fun_str

>> @@ -45,21 +53,33 @@ def camel_to_upper(value: str) -> str:

>>   def c_enum_const(type_name: str,

>>                    const_name: str,

>>                    prefix: Optional[str] = None) -> str:

>> +    """

>> +    Generate a C enumeration constant name.

>> +

>> +    :param type_name: The name of the enumeration.

>> +    :param const_name: The name of this constant.

>> +    :param prefix: Optional, prefix that overrides the type_name.

>> +    """

>>       if prefix is not None:

>>           type_name = prefix

>>       return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()

>>   

>>   

>> -# Map @name to a valid C identifier.

>> -# If @protect, avoid returning certain ticklish identifiers (like

>> -# C keywords) by prepending 'q_'.

>> -#

>> -# Used for converting 'name' from a 'name':'type' qapi definition

>> -# into a generated struct member, as well as converting type names

>> -# into substrings of a generated C function name.

>> -# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

>> -# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

>>   def c_name(name: str, protect: bool = True) -> str:

>> +    """

>> +    Map `name` to a valid C identifier.

>> +

>> +    Used for converting 'name' from a 'name':'type' qapi definition

>> +    into a generated struct member, as well as converting type names

>> +    into substrings of a generated C function name.

>> +

>> +    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

>> +    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

>> +

>> +    :param name: The name to map.

>> +    :param protect: If true, avoid returning certain ticklish identifiers

>> +                    (like C keywords) by prepending ``q_``.

>> +    """

>>       # ANSI X3J11/88-090, 3.1.1

>>       c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',

>>                        'default', 'do', 'double', 'else', 'enum', 'extern',

>> @@ -134,9 +154,12 @@ def decrease(self, amount: int = 4) -> int:

>>   indent = Indentation()

>>   

>>   

>> -# Generate @code with @kwds interpolated.

>> -# Obey indent, and strip EATSPACE.

>>   def cgen(code: str, **kwds: object) -> str:

>> +    """

>> +    Generate `code` with `kwds` interpolated.

>> +

>> +    Obey `indent`, and strip `EATSPACE`.

>> +    """

> 

> This probably won't help on IDEs (never checked any), but sphinx will

> let you do:

> 

>     """

>     Generate `code` with `kwds` interpolated.

> 

>     Obey `indent`, and strip :data:`EATSPACE`.

>     """

> 

> I'm not sure that a maximum level of docstring "sphinxzation" is the

> goal here, though.

> 

> Reviewed-by: Cleber Rosa <crosa@redhat.com>

> 


It isn't yet, but I intend to address that when I remove 
missing-docstring from pylint exemptions. Do I need :data: if I set the 
default role to 'any'?

I'll probably try to enable sphinx at that time (and put the docs in a 
devel/python manual?) and worry about the formatting at that point.

--js
Cleber Rosa Sept. 25, 2020, 5:02 p.m. UTC | #4
On Wed, Sep 23, 2020 at 05:18:54PM -0400, John Snow wrote:
> On 9/23/20 3:38 PM, Cleber Rosa wrote:

> > On Tue, Sep 22, 2020 at 05:00:37PM -0400, John Snow wrote:

> > > As docstrings, they'll show up in documentation and IDE help.

> > > 

> > > Signed-off-by: John Snow <jsnow@redhat.com>

> > > ---

> > >   scripts/qapi/common.py | 51 ++++++++++++++++++++++++++++++------------

> > >   1 file changed, 37 insertions(+), 14 deletions(-)

> > > 

> > > diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py

> > > index 0ce4a107e6..730283722a 100644

> > > --- a/scripts/qapi/common.py

> > > +++ b/scripts/qapi/common.py

> > > @@ -20,10 +20,18 @@

> > >   _C_NAME_TRANS = str.maketrans('.-', '__')

> > > -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1

> > > -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2

> > > -# ENUM24_Name -> ENUM24_NAME

> > >   def camel_to_upper(value: str) -> str:

> > > +    """

> > > +    Converts CamelCase to CAMEL_CASE.

> > > +

> > > +    Examples:

> > > +      ENUMName -> ENUM_NAME

> > > +      EnumName1 -> ENUM_NAME1

> > > +      ENUM_NAME -> ENUM_NAME

> > > +      ENUM_NAME1 -> ENUM_NAME1

> > > +      ENUM_Name2 -> ENUM_NAME2

> > > +      ENUM24_Name -> ENUM24_NAME

> > > +    """

> > >       c_fun_str = c_name(value, False)

> > >       if value.isupper():

> > >           return c_fun_str

> > > @@ -45,21 +53,33 @@ def camel_to_upper(value: str) -> str:

> > >   def c_enum_const(type_name: str,

> > >                    const_name: str,

> > >                    prefix: Optional[str] = None) -> str:

> > > +    """

> > > +    Generate a C enumeration constant name.

> > > +

> > > +    :param type_name: The name of the enumeration.

> > > +    :param const_name: The name of this constant.

> > > +    :param prefix: Optional, prefix that overrides the type_name.

> > > +    """

> > >       if prefix is not None:

> > >           type_name = prefix

> > >       return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()

> > > -# Map @name to a valid C identifier.

> > > -# If @protect, avoid returning certain ticklish identifiers (like

> > > -# C keywords) by prepending 'q_'.

> > > -#

> > > -# Used for converting 'name' from a 'name':'type' qapi definition

> > > -# into a generated struct member, as well as converting type names

> > > -# into substrings of a generated C function name.

> > > -# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

> > > -# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

> > >   def c_name(name: str, protect: bool = True) -> str:

> > > +    """

> > > +    Map `name` to a valid C identifier.

> > > +

> > > +    Used for converting 'name' from a 'name':'type' qapi definition

> > > +    into a generated struct member, as well as converting type names

> > > +    into substrings of a generated C function name.

> > > +

> > > +    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

> > > +    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

> > > +

> > > +    :param name: The name to map.

> > > +    :param protect: If true, avoid returning certain ticklish identifiers

> > > +                    (like C keywords) by prepending ``q_``.

> > > +    """

> > >       # ANSI X3J11/88-090, 3.1.1

> > >       c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',

> > >                        'default', 'do', 'double', 'else', 'enum', 'extern',

> > > @@ -134,9 +154,12 @@ def decrease(self, amount: int = 4) -> int:

> > >   indent = Indentation()

> > > -# Generate @code with @kwds interpolated.

> > > -# Obey indent, and strip EATSPACE.

> > >   def cgen(code: str, **kwds: object) -> str:

> > > +    """

> > > +    Generate `code` with `kwds` interpolated.

> > > +

> > > +    Obey `indent`, and strip `EATSPACE`.

> > > +    """

> > 

> > This probably won't help on IDEs (never checked any), but sphinx will

> > let you do:

> > 

> >     """

> >     Generate `code` with `kwds` interpolated.

> > 

> >     Obey `indent`, and strip :data:`EATSPACE`.

> >     """

> > 

> > I'm not sure that a maximum level of docstring "sphinxzation" is the

> > goal here, though.

> > 

> > Reviewed-by: Cleber Rosa <crosa@redhat.com>

> > 

> 

> It isn't yet, but I intend to address that when I remove missing-docstring

> from pylint exemptions. Do I need :data: if I set the default role to 'any'?

>


That's a good question.  According to the docs "any" will do its best,
so it's probably a good fallback.  I do still favor using the correct
role from the start if I can help it.

> I'll probably try to enable sphinx at that time (and put the docs in a

> devel/python manual?) and worry about the formatting at that point.

> 

> --js


Nice!

- Cleber.
John Snow Sept. 25, 2020, 5:13 p.m. UTC | #5
On 9/25/20 1:02 PM, Cleber Rosa wrote:
> On Wed, Sep 23, 2020 at 05:18:54PM -0400, John Snow wrote:

>> On 9/23/20 3:38 PM, Cleber Rosa wrote:

>>> On Tue, Sep 22, 2020 at 05:00:37PM -0400, John Snow wrote:

>>>> As docstrings, they'll show up in documentation and IDE help.

>>>>

>>>> Signed-off-by: John Snow <jsnow@redhat.com>

>>>> ---

>>>>    scripts/qapi/common.py | 51 ++++++++++++++++++++++++++++++------------

>>>>    1 file changed, 37 insertions(+), 14 deletions(-)

>>>>

>>>> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py

>>>> index 0ce4a107e6..730283722a 100644

>>>> --- a/scripts/qapi/common.py

>>>> +++ b/scripts/qapi/common.py

>>>> @@ -20,10 +20,18 @@

>>>>    _C_NAME_TRANS = str.maketrans('.-', '__')

>>>> -# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1

>>>> -# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2

>>>> -# ENUM24_Name -> ENUM24_NAME

>>>>    def camel_to_upper(value: str) -> str:

>>>> +    """

>>>> +    Converts CamelCase to CAMEL_CASE.

>>>> +

>>>> +    Examples:

>>>> +      ENUMName -> ENUM_NAME

>>>> +      EnumName1 -> ENUM_NAME1

>>>> +      ENUM_NAME -> ENUM_NAME

>>>> +      ENUM_NAME1 -> ENUM_NAME1

>>>> +      ENUM_Name2 -> ENUM_NAME2

>>>> +      ENUM24_Name -> ENUM24_NAME

>>>> +    """

>>>>        c_fun_str = c_name(value, False)

>>>>        if value.isupper():

>>>>            return c_fun_str

>>>> @@ -45,21 +53,33 @@ def camel_to_upper(value: str) -> str:

>>>>    def c_enum_const(type_name: str,

>>>>                     const_name: str,

>>>>                     prefix: Optional[str] = None) -> str:

>>>> +    """

>>>> +    Generate a C enumeration constant name.

>>>> +

>>>> +    :param type_name: The name of the enumeration.

>>>> +    :param const_name: The name of this constant.

>>>> +    :param prefix: Optional, prefix that overrides the type_name.

>>>> +    """

>>>>        if prefix is not None:

>>>>            type_name = prefix

>>>>        return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()

>>>> -# Map @name to a valid C identifier.

>>>> -# If @protect, avoid returning certain ticklish identifiers (like

>>>> -# C keywords) by prepending 'q_'.

>>>> -#

>>>> -# Used for converting 'name' from a 'name':'type' qapi definition

>>>> -# into a generated struct member, as well as converting type names

>>>> -# into substrings of a generated C function name.

>>>> -# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

>>>> -# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

>>>>    def c_name(name: str, protect: bool = True) -> str:

>>>> +    """

>>>> +    Map `name` to a valid C identifier.

>>>> +

>>>> +    Used for converting 'name' from a 'name':'type' qapi definition

>>>> +    into a generated struct member, as well as converting type names

>>>> +    into substrings of a generated C function name.

>>>> +

>>>> +    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'

>>>> +    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'

>>>> +

>>>> +    :param name: The name to map.

>>>> +    :param protect: If true, avoid returning certain ticklish identifiers

>>>> +                    (like C keywords) by prepending ``q_``.

>>>> +    """

>>>>        # ANSI X3J11/88-090, 3.1.1

>>>>        c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',

>>>>                         'default', 'do', 'double', 'else', 'enum', 'extern',

>>>> @@ -134,9 +154,12 @@ def decrease(self, amount: int = 4) -> int:

>>>>    indent = Indentation()

>>>> -# Generate @code with @kwds interpolated.

>>>> -# Obey indent, and strip EATSPACE.

>>>>    def cgen(code: str, **kwds: object) -> str:

>>>> +    """

>>>> +    Generate `code` with `kwds` interpolated.

>>>> +

>>>> +    Obey `indent`, and strip `EATSPACE`.

>>>> +    """

>>>

>>> This probably won't help on IDEs (never checked any), but sphinx will

>>> let you do:

>>>

>>>      """

>>>      Generate `code` with `kwds` interpolated.

>>>

>>>      Obey `indent`, and strip :data:`EATSPACE`.

>>>      """

>>>

>>> I'm not sure that a maximum level of docstring "sphinxzation" is the

>>> goal here, though.

>>>

>>> Reviewed-by: Cleber Rosa <crosa@redhat.com>

>>>

>>

>> It isn't yet, but I intend to address that when I remove missing-docstring

>> from pylint exemptions. Do I need :data: if I set the default role to 'any'?

>>

> 

> That's a good question.  According to the docs "any" will do its best,

> so it's probably a good fallback.  I do still favor using the correct

> role from the start if I can help it.

> 

>> I'll probably try to enable sphinx at that time (and put the docs in a

>> devel/python manual?) and worry about the formatting at that point.

>>

>> --js

> 

> Nice!

> 

> - Cleber.

> 


As of v3, I started toying with this, as you can see. It is a goal of 
mine to hit full doc coverage in this package, eventually.

What I learned: you can reference data members, but only if they have a 
comment. Otherwise, they are skipped. Sphinx does not appear to offer an 
"undocumented data member" option the same way it does for "undocumented 
member".

Using the "Any" role is nice, and I prefer it. If it finds that a target 
is ambiguous (2+ references), it will throw an error and the sphinx 
build will fail. This is good enough for me: there's no reason to 
clutter the docstrings with Sphinxese if we don't have to.

I would like to try and keep these readable to humans who are just in 
emacs/vim editing code, too.

--js
diff mbox series

Patch

diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 0ce4a107e6..730283722a 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -20,10 +20,18 @@ 
 _C_NAME_TRANS = str.maketrans('.-', '__')
 
 
-# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
-# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
-# ENUM24_Name -> ENUM24_NAME
 def camel_to_upper(value: str) -> str:
+    """
+    Converts CamelCase to CAMEL_CASE.
+
+    Examples:
+      ENUMName -> ENUM_NAME
+      EnumName1 -> ENUM_NAME1
+      ENUM_NAME -> ENUM_NAME
+      ENUM_NAME1 -> ENUM_NAME1
+      ENUM_Name2 -> ENUM_NAME2
+      ENUM24_Name -> ENUM24_NAME
+    """
     c_fun_str = c_name(value, False)
     if value.isupper():
         return c_fun_str
@@ -45,21 +53,33 @@  def camel_to_upper(value: str) -> str:
 def c_enum_const(type_name: str,
                  const_name: str,
                  prefix: Optional[str] = None) -> str:
+    """
+    Generate a C enumeration constant name.
+
+    :param type_name: The name of the enumeration.
+    :param const_name: The name of this constant.
+    :param prefix: Optional, prefix that overrides the type_name.
+    """
     if prefix is not None:
         type_name = prefix
     return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
 
 
-# Map @name to a valid C identifier.
-# If @protect, avoid returning certain ticklish identifiers (like
-# C keywords) by prepending 'q_'.
-#
-# Used for converting 'name' from a 'name':'type' qapi definition
-# into a generated struct member, as well as converting type names
-# into substrings of a generated C function name.
-# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
-# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
 def c_name(name: str, protect: bool = True) -> str:
+    """
+    Map `name` to a valid C identifier.
+
+    Used for converting 'name' from a 'name':'type' qapi definition
+    into a generated struct member, as well as converting type names
+    into substrings of a generated C function name.
+
+    '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
+    protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
+
+    :param name: The name to map.
+    :param protect: If true, avoid returning certain ticklish identifiers
+                    (like C keywords) by prepending ``q_``.
+    """
     # ANSI X3J11/88-090, 3.1.1
     c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
                      'default', 'do', 'double', 'else', 'enum', 'extern',
@@ -134,9 +154,12 @@  def decrease(self, amount: int = 4) -> int:
 indent = Indentation()
 
 
-# Generate @code with @kwds interpolated.
-# Obey indent, and strip EATSPACE.
 def cgen(code: str, **kwds: object) -> str:
+    """
+    Generate `code` with `kwds` interpolated.
+
+    Obey `indent`, and strip `EATSPACE`.
+    """
     raw = code % kwds
     if indent:
         raw = re.sub(r'^(?!(#|$))', str(indent), raw, flags=re.MULTILINE)