nameparser 1.3.1__tar.gz → 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. nameparser-2.0.0/PKG-INFO +113 -0
  2. nameparser-2.0.0/README.rst +87 -0
  3. nameparser-2.0.0/nameparser/__init__.py +42 -0
  4. nameparser-2.0.0/nameparser/__main__.py +48 -0
  5. nameparser-2.0.0/nameparser/_config_shim.py +1167 -0
  6. nameparser-2.0.0/nameparser/_facade.py +724 -0
  7. nameparser-2.0.0/nameparser/_lexicon.py +597 -0
  8. nameparser-2.0.0/nameparser/_locale.py +81 -0
  9. nameparser-2.0.0/nameparser/_parser.py +192 -0
  10. nameparser-2.0.0/nameparser/_pipeline/__init__.py +37 -0
  11. nameparser-2.0.0/nameparser/_pipeline/_assemble.py +66 -0
  12. nameparser-2.0.0/nameparser/_pipeline/_assign.py +276 -0
  13. nameparser-2.0.0/nameparser/_pipeline/_classify.py +95 -0
  14. nameparser-2.0.0/nameparser/_pipeline/_extract.py +241 -0
  15. nameparser-2.0.0/nameparser/_pipeline/_group.py +341 -0
  16. nameparser-2.0.0/nameparser/_pipeline/_post_rules.py +129 -0
  17. nameparser-2.0.0/nameparser/_pipeline/_segment.py +122 -0
  18. nameparser-2.0.0/nameparser/_pipeline/_state.py +94 -0
  19. nameparser-2.0.0/nameparser/_pipeline/_tokenize.py +125 -0
  20. nameparser-2.0.0/nameparser/_pipeline/_vocab.py +126 -0
  21. nameparser-2.0.0/nameparser/_policy.py +504 -0
  22. nameparser-2.0.0/nameparser/_render.py +165 -0
  23. nameparser-2.0.0/nameparser/_types.py +658 -0
  24. nameparser-2.0.0/nameparser/_version.py +9 -0
  25. nameparser-2.0.0/nameparser/config/__init__.py +20 -0
  26. nameparser-2.0.0/nameparser/config/_invariants.py +27 -0
  27. nameparser-2.0.0/nameparser/config/bound_first_names.py +28 -0
  28. nameparser-2.0.0/nameparser/config/capitalization.py +16 -0
  29. nameparser-2.0.0/nameparser/config/conjunctions.py +33 -0
  30. nameparser-2.0.0/nameparser/config/maiden_markers.py +42 -0
  31. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser/config/prefixes.py +33 -0
  32. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser/config/regexes.py +12 -6
  33. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser/config/suffixes.py +50 -10
  34. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser/config/titles.py +105 -3
  35. nameparser-2.0.0/nameparser/locales/__init__.py +62 -0
  36. nameparser-2.0.0/nameparser/locales/ru.py +59 -0
  37. nameparser-2.0.0/nameparser/locales/tr_az.py +49 -0
  38. nameparser-2.0.0/nameparser/parser.py +6 -0
  39. nameparser-2.0.0/nameparser/util.py +13 -0
  40. nameparser-2.0.0/nameparser.egg-info/PKG-INFO +113 -0
  41. nameparser-2.0.0/nameparser.egg-info/SOURCES.txt +100 -0
  42. {nameparser-1.3.1 → nameparser-2.0.0}/pyproject.toml +32 -5
  43. {nameparser-1.3.1 → nameparser-2.0.0}/tests/base.py +8 -2
  44. nameparser-2.0.0/tests/conftest.py +81 -0
  45. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_bound_first_names.py +3 -8
  46. nameparser-2.0.0/tests/test_comma_variants.py +34 -0
  47. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_constants.py +424 -354
  48. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_east_slavic_patronymic_order.py +21 -18
  49. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_first_name.py +4 -4
  50. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_initials.py +37 -44
  51. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_nicknames.py +31 -62
  52. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_output_format.py +42 -41
  53. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_prefixes.py +5 -3
  54. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_python_api.py +95 -142
  55. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_suffixes.py +13 -6
  56. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_titles.py +18 -1
  57. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_turkic_patronymic_order.py +23 -15
  58. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_variations.py +6 -2
  59. nameparser-2.0.0/tests/v2/__init__.py +0 -0
  60. nameparser-2.0.0/tests/v2/cases.py +469 -0
  61. nameparser-2.0.0/tests/v2/conftest.py +36 -0
  62. nameparser-2.0.0/tests/v2/pipeline/__init__.py +0 -0
  63. nameparser-2.0.0/tests/v2/pipeline/test_assemble.py +130 -0
  64. nameparser-2.0.0/tests/v2/pipeline/test_assign.py +171 -0
  65. nameparser-2.0.0/tests/v2/pipeline/test_classify.py +78 -0
  66. nameparser-2.0.0/tests/v2/pipeline/test_extract.py +259 -0
  67. nameparser-2.0.0/tests/v2/pipeline/test_group.py +161 -0
  68. nameparser-2.0.0/tests/v2/pipeline/test_post_rules.py +122 -0
  69. nameparser-2.0.0/tests/v2/pipeline/test_segment.py +108 -0
  70. nameparser-2.0.0/tests/v2/pipeline/test_state.py +110 -0
  71. nameparser-2.0.0/tests/v2/pipeline/test_tokenize.py +91 -0
  72. nameparser-2.0.0/tests/v2/pipeline/test_vocab.py +40 -0
  73. nameparser-2.0.0/tests/v2/test_benchmark.py +122 -0
  74. nameparser-2.0.0/tests/v2/test_cases.py +26 -0
  75. nameparser-2.0.0/tests/v2/test_cli.py +62 -0
  76. nameparser-2.0.0/tests/v2/test_config_shim.py +816 -0
  77. nameparser-2.0.0/tests/v2/test_contracts.py +84 -0
  78. nameparser-2.0.0/tests/v2/test_facade.py +561 -0
  79. nameparser-2.0.0/tests/v2/test_facade_cases.py +75 -0
  80. nameparser-2.0.0/tests/v2/test_layering.py +224 -0
  81. nameparser-2.0.0/tests/v2/test_lexicon.py +558 -0
  82. nameparser-2.0.0/tests/v2/test_locale.py +76 -0
  83. nameparser-2.0.0/tests/v2/test_locales.py +550 -0
  84. nameparser-2.0.0/tests/v2/test_parser.py +438 -0
  85. nameparser-2.0.0/tests/v2/test_policy.py +448 -0
  86. nameparser-2.0.0/tests/v2/test_properties.py +352 -0
  87. nameparser-2.0.0/tests/v2/test_regex_sync.py +151 -0
  88. nameparser-2.0.0/tests/v2/test_render.py +290 -0
  89. nameparser-2.0.0/tests/v2/test_reprs.py +133 -0
  90. nameparser-2.0.0/tests/v2/test_types.py +454 -0
  91. nameparser-1.3.1/PKG-INFO +0 -200
  92. nameparser-1.3.1/README.rst +0 -172
  93. nameparser-1.3.1/nameparser/__init__.py +0 -7
  94. nameparser-1.3.1/nameparser/__main__.py +0 -31
  95. nameparser-1.3.1/nameparser/_version.py +0 -2
  96. nameparser-1.3.1/nameparser/config/__init__.py +0 -861
  97. nameparser-1.3.1/nameparser/config/bound_first_names.py +0 -12
  98. nameparser-1.3.1/nameparser/config/capitalization.py +0 -10
  99. nameparser-1.3.1/nameparser/config/conjunctions.py +0 -15
  100. nameparser-1.3.1/nameparser/parser.py +0 -1595
  101. nameparser-1.3.1/nameparser/util.py +0 -16
  102. nameparser-1.3.1/nameparser.egg-info/PKG-INFO +0 -200
  103. nameparser-1.3.1/nameparser.egg-info/SOURCES.txt +0 -46
  104. nameparser-1.3.1/nameparser.egg-info/requires.txt +0 -3
  105. nameparser-1.3.1/tests/conftest.py +0 -68
  106. nameparser-1.3.1/tests/test_config_attribute_docstrings.py +0 -79
  107. nameparser-1.3.1/tests/test_parser_util.py +0 -39
  108. {nameparser-1.3.1 → nameparser-2.0.0}/AUTHORS +0 -0
  109. {nameparser-1.3.1 → nameparser-2.0.0}/LICENSE +0 -0
  110. {nameparser-1.3.1 → nameparser-2.0.0}/MANIFEST.in +0 -0
  111. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser/py.typed +0 -0
  112. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser.egg-info/dependency_links.txt +0 -0
  113. {nameparser-1.3.1 → nameparser-2.0.0}/nameparser.egg-info/top_level.txt +0 -0
  114. {nameparser-1.3.1 → nameparser-2.0.0}/setup.cfg +0 -0
  115. {nameparser-1.3.1 → nameparser-2.0.0}/tests/__init__.py +0 -0
  116. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_brute_force.py +0 -0
  117. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_capitalization.py +0 -0
  118. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_conjunctions.py +0 -0
  119. {nameparser-1.3.1 → nameparser-2.0.0}/tests/test_middle_name_as_last.py +0 -0
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.4
2
+ Name: nameparser
3
+ Version: 2.0.0
4
+ Summary: A simple Python module for parsing human names into their individual components.
5
+ Author-email: Derek Gulbranson <derek73@gmail.com>
6
+ License: LGPL
7
+ Keywords: names,parser
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Development Status :: 5 - Production/Stable
18
+ Classifier: Natural Language :: English
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: Text Processing :: Linguistic
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/x-rst
23
+ License-File: LICENSE
24
+ License-File: AUTHORS
25
+ Dynamic: license-file
26
+
27
+ Name Parser
28
+ ===========
29
+
30
+ |Build Status| |PyPI| |PyPI version| |Documentation| |License| |Downloads| |Codecov|
31
+
32
+ nameparser parses human names into seven fields — title, given, middle,
33
+ family, suffix, nickname, maiden. Results are immutable, configuration is
34
+ composable, and locale packs are opt-in.
35
+
36
+ 📣 **nameparser 2.0 is out.** Existing ``HumanName`` code keeps working
37
+ through 2.x — most 1.x code needs no changes. The `migration guide
38
+ <https://nameparser.readthedocs.io/en/latest/migrate.html>`__ has the
39
+ field-by-field map, and anything the migration missed can be reported
40
+ on `the discussion issue
41
+ <https://github.com/derek73/python-nameparser/issues/284>`__.
42
+
43
+ Installation
44
+ ------------
45
+
46
+ ::
47
+
48
+ pip install nameparser
49
+
50
+ Requires Python 3.11+.
51
+
52
+ Quick Start Example
53
+ --------------------
54
+
55
+ .. code-block:: python
56
+
57
+ >>> from nameparser import parse
58
+ >>> name = parse("Dr. Juan Q. Xavier de la Vega III")
59
+ >>> name.given, name.family
60
+ ('Juan', 'de la Vega')
61
+ >>> name.render("{family}, {given}")
62
+ 'de la Vega, Juan'
63
+
64
+ Those seven fields are ``title``, ``given``, ``middle``, ``family``,
65
+ ``suffix``, ``nickname``, and ``maiden`` — plus aggregate views like
66
+ ``given_names``, ``surnames``, ``family_base``, and ``family_particles``
67
+ for combining or splitting them further.
68
+
69
+ Learn more
70
+ ----------
71
+
72
+ * `Using the parser <https://nameparser.readthedocs.io/en/latest/usage.html>`__ — the full tour: input shapes, aggregates, rendering, comparison, ambiguities, tokens
73
+ * `Customizing the parser <https://nameparser.readthedocs.io/en/latest/customize.html>`__ — vocabulary, behavior, and presentation
74
+ * `Locale packs <https://nameparser.readthedocs.io/en/latest/locales.html>`__ — opt-in bundles for East Slavic patronymics, Turkic markers, and more
75
+ * There's also a CLI: ``python -m nameparser --json "Doe, John"``
76
+
77
+ Coming from 1.x
78
+ ----------------
79
+
80
+ ``HumanName`` and ``CONSTANTS`` keep working in 2.0 — same imports, same
81
+ attributes, same mutation API. What 2.0 removes is the batch of
82
+ deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
83
+ 1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
84
+ Two things that check will not catch: four removals 1.4 never warned
85
+ about (three raise on contact, the fourth only warns), and one that
86
+ changes results silently — ``name == "John Smith"`` is now ``False``.
87
+ `Migrating from HumanName <https://nameparser.readthedocs.io/en/latest/migrate.html>`__
88
+ covers both, and translates a v1 customization into the new API whenever
89
+ that's convenient for you.
90
+
91
+ See the `release log <https://nameparser.readthedocs.io/en/latest/release_log.html>`__
92
+ for the full list of changes in the 2.0 series.
93
+
94
+ License
95
+ -------
96
+
97
+ LGPL licensed. See `LICENSE <https://github.com/derek73/python-nameparser/blob/master/LICENSE>`__
98
+ for details.
99
+
100
+ .. |Build Status| image:: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml/badge.svg
101
+ :target: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml
102
+ .. |PyPI| image:: https://img.shields.io/pypi/v/nameparser.svg
103
+ :target: https://pypi.org/project/nameparser/
104
+ .. |Documentation| image:: https://readthedocs.org/projects/nameparser/badge/?version=latest
105
+ :target: http://nameparser.readthedocs.io/en/latest/?badge=latest
106
+ .. |PyPI version| image:: https://img.shields.io/pypi/pyversions/nameparser.svg
107
+ :target: https://pypi.org/project/nameparser/
108
+ .. |License| image:: https://img.shields.io/pypi/l/nameparser.svg
109
+ :target: https://pypi.org/project/nameparser/
110
+ .. |Downloads| image:: https://static.pepy.tech/badge/nameparser
111
+ :target: https://pepy.tech/project/nameparser
112
+ .. |Codecov| image:: https://codecov.io/gh/derek73/python-nameparser/branch/master/graph/badge.svg
113
+ :target: https://codecov.io/gh/derek73/python-nameparser
@@ -0,0 +1,87 @@
1
+ Name Parser
2
+ ===========
3
+
4
+ |Build Status| |PyPI| |PyPI version| |Documentation| |License| |Downloads| |Codecov|
5
+
6
+ nameparser parses human names into seven fields — title, given, middle,
7
+ family, suffix, nickname, maiden. Results are immutable, configuration is
8
+ composable, and locale packs are opt-in.
9
+
10
+ 📣 **nameparser 2.0 is out.** Existing ``HumanName`` code keeps working
11
+ through 2.x — most 1.x code needs no changes. The `migration guide
12
+ <https://nameparser.readthedocs.io/en/latest/migrate.html>`__ has the
13
+ field-by-field map, and anything the migration missed can be reported
14
+ on `the discussion issue
15
+ <https://github.com/derek73/python-nameparser/issues/284>`__.
16
+
17
+ Installation
18
+ ------------
19
+
20
+ ::
21
+
22
+ pip install nameparser
23
+
24
+ Requires Python 3.11+.
25
+
26
+ Quick Start Example
27
+ --------------------
28
+
29
+ .. code-block:: python
30
+
31
+ >>> from nameparser import parse
32
+ >>> name = parse("Dr. Juan Q. Xavier de la Vega III")
33
+ >>> name.given, name.family
34
+ ('Juan', 'de la Vega')
35
+ >>> name.render("{family}, {given}")
36
+ 'de la Vega, Juan'
37
+
38
+ Those seven fields are ``title``, ``given``, ``middle``, ``family``,
39
+ ``suffix``, ``nickname``, and ``maiden`` — plus aggregate views like
40
+ ``given_names``, ``surnames``, ``family_base``, and ``family_particles``
41
+ for combining or splitting them further.
42
+
43
+ Learn more
44
+ ----------
45
+
46
+ * `Using the parser <https://nameparser.readthedocs.io/en/latest/usage.html>`__ — the full tour: input shapes, aggregates, rendering, comparison, ambiguities, tokens
47
+ * `Customizing the parser <https://nameparser.readthedocs.io/en/latest/customize.html>`__ — vocabulary, behavior, and presentation
48
+ * `Locale packs <https://nameparser.readthedocs.io/en/latest/locales.html>`__ — opt-in bundles for East Slavic patronymics, Turkic markers, and more
49
+ * There's also a CLI: ``python -m nameparser --json "Doe, John"``
50
+
51
+ Coming from 1.x
52
+ ----------------
53
+
54
+ ``HumanName`` and ``CONSTANTS`` keep working in 2.0 — same imports, same
55
+ attributes, same mutation API. What 2.0 removes is the batch of
56
+ deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
57
+ 1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
58
+ Two things that check will not catch: four removals 1.4 never warned
59
+ about (three raise on contact, the fourth only warns), and one that
60
+ changes results silently — ``name == "John Smith"`` is now ``False``.
61
+ `Migrating from HumanName <https://nameparser.readthedocs.io/en/latest/migrate.html>`__
62
+ covers both, and translates a v1 customization into the new API whenever
63
+ that's convenient for you.
64
+
65
+ See the `release log <https://nameparser.readthedocs.io/en/latest/release_log.html>`__
66
+ for the full list of changes in the 2.0 series.
67
+
68
+ License
69
+ -------
70
+
71
+ LGPL licensed. See `LICENSE <https://github.com/derek73/python-nameparser/blob/master/LICENSE>`__
72
+ for details.
73
+
74
+ .. |Build Status| image:: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml/badge.svg
75
+ :target: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml
76
+ .. |PyPI| image:: https://img.shields.io/pypi/v/nameparser.svg
77
+ :target: https://pypi.org/project/nameparser/
78
+ .. |Documentation| image:: https://readthedocs.org/projects/nameparser/badge/?version=latest
79
+ :target: http://nameparser.readthedocs.io/en/latest/?badge=latest
80
+ .. |PyPI version| image:: https://img.shields.io/pypi/pyversions/nameparser.svg
81
+ :target: https://pypi.org/project/nameparser/
82
+ .. |License| image:: https://img.shields.io/pypi/l/nameparser.svg
83
+ :target: https://pypi.org/project/nameparser/
84
+ .. |Downloads| image:: https://static.pepy.tech/badge/nameparser
85
+ :target: https://pepy.tech/project/nameparser
86
+ .. |Codecov| image:: https://codecov.io/gh/derek73/python-nameparser/branch/master/graph/badge.svg
87
+ :target: https://codecov.io/gh/derek73/python-nameparser
@@ -0,0 +1,42 @@
1
+ from nameparser._version import VERSION as VERSION
2
+ from nameparser._version import __version__ as __version__
3
+ from nameparser.parser import HumanName as HumanName
4
+ __author__ = "Derek Gulbranson"
5
+ __author_email__ = 'derek73@gmail.com'
6
+ __license__ = "LGPL"
7
+ __url__ = "https://github.com/derek73/python-nameparser"
8
+
9
+ from nameparser._lexicon import Lexicon
10
+ from nameparser._locale import Locale
11
+ from nameparser._parser import Parser, parse, parser_for
12
+ from nameparser._policy import (
13
+ DEFAULT_NICKNAME_DELIMITERS,
14
+ FAMILY_FIRST,
15
+ FAMILY_FIRST_GIVEN_LAST,
16
+ GIVEN_FIRST,
17
+ UNSET,
18
+ PatronymicRule,
19
+ Policy,
20
+ PolicyPatch,
21
+ )
22
+ from nameparser._types import (
23
+ STABLE_TAGS,
24
+ Ambiguity,
25
+ AmbiguityKind,
26
+ ParsedName,
27
+ Role,
28
+ Span,
29
+ Token,
30
+ )
31
+
32
+ __all__ = [
33
+ # v1 (compatibility layer)
34
+ "HumanName",
35
+ # v2 core
36
+ "Span", "Role", "Token", "Ambiguity", "AmbiguityKind", "ParsedName",
37
+ "STABLE_TAGS",
38
+ "Lexicon", "Policy", "PolicyPatch", "PatronymicRule", "UNSET",
39
+ "GIVEN_FIRST", "FAMILY_FIRST", "FAMILY_FIRST_GIVEN_LAST",
40
+ "DEFAULT_NICKNAME_DELIMITERS", "Locale",
41
+ "Parser", "parse", "parser_for",
42
+ ]
@@ -0,0 +1,48 @@
1
+ """Command-line debug helper over the 2.0 API (migration spec §6).
2
+
3
+ python -m nameparser "Dr. Juan Q. Xavier de la Vega III"
4
+ python -m nameparser --json "Doe, John"
5
+ """
6
+ import argparse
7
+ import json
8
+
9
+ from nameparser import parse
10
+
11
+
12
+ def main(argv: list[str] | None = None) -> int:
13
+ ap = argparse.ArgumentParser(
14
+ prog="nameparser", description="Parse a personal name.")
15
+ ap.add_argument("name", help="the name string to parse")
16
+ ap.add_argument("--json", action="store_true",
17
+ help="print the component dict as JSON")
18
+ ap.add_argument("--locale", metavar="CODE",
19
+ help="parse with a locale pack (e.g. 'ru'); see "
20
+ "nameparser.locales")
21
+ args = ap.parse_args(argv)
22
+ # `is not None`, not truthiness: --locale "" must reach get() and
23
+ # exit 2 listing the codes, not silently fall back to the default
24
+ if args.locale is not None:
25
+ from nameparser import locales, parser_for
26
+ try:
27
+ parser = parser_for(locales.get(args.locale))
28
+ except KeyError as exc:
29
+ ap.error(exc.args[0]) # exits 2, message to stderr
30
+ n = parser.parse(args.name)
31
+ else:
32
+ n = parse(args.name)
33
+ if args.json:
34
+ print(json.dumps(n.as_dict(), ensure_ascii=False))
35
+ return 0
36
+ # Label each section: the two reprs are byte-identical for input
37
+ # that is already correctly cased, so without labels there is no
38
+ # telling which is the parse and which is the capitalized view.
39
+ print("Parsed:")
40
+ print(repr(n))
41
+ print("Capitalized:")
42
+ print(repr(n.capitalized()))
43
+ print("Initials:", n.initials())
44
+ return 0
45
+
46
+
47
+ if __name__ == "__main__":
48
+ raise SystemExit(main())