Skip to content

render(): write one field as initials, e.g. "Maria F." or "M. Ferreira" #1013

Open

Description

@derek73

A caller who wants "Maria F." or "M. Ferreira" today has to join two calls, because render() writes a field only in full and initials() writes every field it is given as initials:

name = parse("Maria Santos Ferreira")
name.render("{given}") + " " + name.initials("{family}")   # 'Maria F.'
name.render("{given} {family:initial}")                    # ValueError: Invalid format specifier

The glue is also wrong at the edges: it adds a stray space when one side is empty, which render()'s collapse (#254) would have removed. Basecamp's name_of_person gem ships these two views as familiar and abbreviated. Its first/last split is far simpler than ours, but the views themselves are reasonable things to want.

Proposal, in rule shape

When: a render() spec marks a field with the !i conversion, as in "{given} {family!i}".

Then: that field is written as the initials initials() gives for that one group, with the default delimiter . and separator , and the rest of the spec renders as it does now, collapse included.

Because: the initials view already settles which words initial and in what order (rules/R3, initials honor the fold; rules/R7, no initials in a script that writes none). One spec that mixes full fields with initials should reuse those answers, not create a second set of them.

  • Except: only given, middle and family take !i, the three groups initials() reads. {title!i}, {suffix!i}, {nickname!i}, {maiden!i} and the derived views ({surnames!i}, {family_base!i}, ...) raise ValueError naming the three. R3 says titles, suffixes and nicknames contribute nothing, and a derived view that spans groups has no single group to initial.
    "Dr. Juan Q. Xavier de la Vega III"  "{title!i} {family}"  →  ValueError
    
  • Except: particles contribute nothing, as in R3.
    "Juan de la Vega"            "{given} {family!i}"   →  "Juan V."
    
  • Except: a script that writes no initials contributes nothing (R7), and the empty field collapses.
    "김민준"                      "{given} {family!i}"   →  "민준"
    
  • Except: a folded family initials in its fold order (R3's initials() ignores the folded-word ordering that the family field applies (der, y van gives y. d. v. vs the facade's y. v. d.) #408 clause).
    "Hassan, Mohamad Ahmad Ali"  "{given} {family!i}"   →  "Mohamad A. A. H."   (middle_as_family=True)
    "Maria Santos Ferreira"      "{given} {family!i}"   →  "Maria S. F."        (middle_as_family=True)
    "Maria Santos Ferreira"      "{given} {family!i}"   →  "Maria F."           (default)
    
  • Precedence: !r, !s and !a keep Python's meaning. A format spec after the conversion applies to the initialled text ({family!i:>4}).
  • Accepted: a hyphenated word gives one initial, as in initials() today ("Jean-Luc Picard", "{given!i} {family}" → "J. Picard", not the French "J.-L. Picard"). That belongs to the initials view, not to this spec, and is a question of its own.
  • Accepted: the delimiter and separator are fixed. A caller who wants "DH" keeps initials("{given}{family}", delimiter="", separator="").

Open questions

  1. A one-word name. parse("Smith") reads given Smith, so "{given!i} {family}" gives "S." and the only name word is reduced to an initial. name_of_person returns the first name whole when the last name is empty. Should !i skip a field when every other field the spec names is empty? Or is this a recipe note ("abbreviate the given name only when there is a family")? A rule that looks at other fields would be the first in render() to do that.
  2. Syntax. !i composes with format specs and leaves the field list alone. The alternatives are a format spec ({family:initial}, which takes over the field's padding and alignment) or derived keys ({family_initials}, no new syntax and listed in the KeyError message, but three more keys and nowhere to extend to). !i is the proposal. Is a one-letter conversion clear enough in the docs?
  3. The default str() and __format__. Is a ParsedName.__format__ that passes its spec to render() (so f"{name:{given} {family!i}}" works) in scope, or a separate question?

Done when

  • render() fills specs through a string.Formatter subclass whose convert_field handles i. The conversion needs the field's tokens, not its text, so the values passed in carry both.
  • A new rule beside R3 and R7 in docs/design/rules/ with the examples above, an index line, and a decisions entry for the syntax chosen.
  • A recipe doctest in docs/usage.rst ("Maria F.", "M. Ferreira") and a release-log bullet.
  • Tests: the field family {given, middle, family} × !i and the refused fields parametrized together, plus each Except row.

Activity

  1. added this to the 3.1 milestone on Nov 3, 2026
  2. self-assigned this
    on Nov 3, 2026
  3. derek73 commented on Nov 6, 2026

    @derek73
    OwnerAuthor

    A use case for this proposal that its "only given, middle and family take !i" exception rules out: the forms that Spanish and Catalan names, and Latin American names especially, initial in.

    A name with two surnames keeps the first (paternal) surname whole, because it is the one that identifies the person, and shortens the second, or drops it:

    Josep A. Lloret P.     (given, second given name as an initial, first surname, second surname as an initial)
    J. A. Lloret           (given names as initials, first surname only)
    Lloret Palol, J. A.    (citation form: given names as initials, both surnames whole)
    

    initials() gives J. A. L. P. for Josep Antoni Lloret Palol under parser_for(locales.ES), initialling the first surname too. The views these forms need already exist: rules/R11's surname1 and rules/R10's surname2 render in a spec today:

    n = parser_for(locales.ES).parse("Josep Antoni Lloret Palol")
    n.render("{given} {surname1} {surname2}")   # 'Josep Lloret Palol'

    So the first two forms would be "{given} {middle!i} {surname1} {surname2!i}" and "{given!i} {middle!i} {surname1}", if !i took surname2 (and surname1, for symmetry). The draft refuses them, with the reason "a derived view that spans groups has no single group to initial". surname1 and surname2 don't span groups: each is one name unit of the family, which is what R11 and R10 exist to mark.

    Two things a clause for them would have to settle:

    • A family comma marks no second surname (rules/R10: "A family comma marks nothing"), so Lloret Palol, Josep Antoni has surname1 'Lloret Palol' and an empty surname2, and "{surname1} {surname2!i}" writes Lloret Palol there. Is the collapse enough, or should the docs warn that this form needs a name with no family comma?
    • Particles: {surname2!i} on Juan García de la Vega should follow R3 and give V., as {family!i} does.

    The third form (Lloret Palol, J. A.) needs nothing new: "{family}, {given!i} {middle!i}" already reaches it under the proposal as written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions