nameparser 1.1.2__tar.gz → 1.2.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 (28) hide show
  1. {nameparser-1.1.2/nameparser.egg-info → nameparser-1.2.0}/PKG-INFO +14 -9
  2. {nameparser-1.1.2 → nameparser-1.2.0}/README.rst +2 -2
  3. nameparser-1.2.0/nameparser/__init__.py +7 -0
  4. nameparser-1.2.0/nameparser/_version.py +2 -0
  5. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/__init__.py +73 -60
  6. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/capitalization.py +1 -4
  7. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/conjunctions.py +1 -4
  8. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/prefixes.py +0 -3
  9. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/regexes.py +7 -16
  10. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/suffixes.py +0 -3
  11. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/config/titles.py +0 -3
  12. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser/parser.py +149 -156
  13. nameparser-1.2.0/nameparser/py.typed +0 -0
  14. nameparser-1.2.0/nameparser/util.py +17 -0
  15. {nameparser-1.1.2 → nameparser-1.2.0/nameparser.egg-info}/PKG-INFO +14 -9
  16. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser.egg-info/SOURCES.txt +4 -2
  17. nameparser-1.2.0/nameparser.egg-info/requires.txt +3 -0
  18. nameparser-1.2.0/pyproject.toml +66 -0
  19. {nameparser-1.1.2 → nameparser-1.2.0}/setup.cfg +0 -3
  20. {nameparser-1.1.2 → nameparser-1.2.0}/tests.py +403 -394
  21. nameparser-1.1.2/nameparser/__init__.py +0 -9
  22. nameparser-1.1.2/nameparser/util.py +0 -39
  23. nameparser-1.1.2/setup.py +0 -37
  24. {nameparser-1.1.2 → nameparser-1.2.0}/AUTHORS +0 -0
  25. {nameparser-1.1.2 → nameparser-1.2.0}/LICENSE +0 -0
  26. {nameparser-1.1.2 → nameparser-1.2.0}/MANIFEST.in +0 -0
  27. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser.egg-info/dependency_links.txt +0 -0
  28. {nameparser-1.1.2 → nameparser-1.2.0}/nameparser.egg-info/top_level.txt +0 -0
@@ -1,32 +1,37 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: nameparser
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: A simple Python module for parsing human names into their individual components.
5
- Home-page: https://github.com/derek73/python-nameparser
6
- Author: Derek Gulbranson
7
- Author-email: derek73@gmail.com
5
+ Author-email: Derek Gulbranson <derek73@gmail.com>
8
6
  License: LGPL
9
7
  Keywords: names,parser
10
8
  Classifier: Intended Audience :: Developers
11
- Classifier: Operating System :: OS Independent
12
9
  Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
10
+ Classifier: Operating System :: OS Independent
13
11
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 2
15
12
  Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
16
18
  Classifier: Development Status :: 5 - Production/Stable
17
19
  Classifier: Natural Language :: English
18
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
21
  Classifier: Topic :: Text Processing :: Linguistic
22
+ Requires-Python: >=3.10
20
23
  Description-Content-Type: text/x-rst
21
24
  License-File: LICENSE
22
25
  License-File: AUTHORS
26
+ Requires-Dist: typing_extensions>=4.5.0; python_version < "3.11"
27
+ Dynamic: license-file
23
28
 
24
29
  Name Parser
25
30
  ===========
26
31
 
27
32
  |Build Status| |PyPI| |PyPI version| |Documentation|
28
33
 
29
- A simple Python (3.2+ & 2.6+) module for parsing human names into their
34
+ A simple Python (3.10+) module for parsing human names into their
30
35
  individual components.
31
36
 
32
37
  * hn.title
@@ -72,7 +77,7 @@ Installation
72
77
  If you want to try out the latest code from GitHub you can
73
78
  install with pip using the command below.
74
79
 
75
- ``pip install -e git+git://github.com/derek73/python-nameparser.git#egg=nameparser``
80
+ ``pip install -e git+https://github.com/derek73/python-nameparser.git``
76
81
 
77
82
  If you need to handle lists of names, check out
78
83
  `namesparser <https://github.com/gwu-libraries/namesparser>`_, a
@@ -3,7 +3,7 @@ Name Parser
3
3
 
4
4
  |Build Status| |PyPI| |PyPI version| |Documentation|
5
5
 
6
- A simple Python (3.2+ & 2.6+) module for parsing human names into their
6
+ A simple Python (3.10+) module for parsing human names into their
7
7
  individual components.
8
8
 
9
9
  * hn.title
@@ -49,7 +49,7 @@ Installation
49
49
  If you want to try out the latest code from GitHub you can
50
50
  install with pip using the command below.
51
51
 
52
- ``pip install -e git+git://github.com/derek73/python-nameparser.git#egg=nameparser``
52
+ ``pip install -e git+https://github.com/derek73/python-nameparser.git``
53
53
 
54
54
  If you need to handle lists of names, check out
55
55
  `namesparser <https://github.com/gwu-libraries/namesparser>`_, a
@@ -0,0 +1,7 @@
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"
@@ -0,0 +1,2 @@
1
+ VERSION = (1, 2, 0)
2
+ __version__ = '.'.join(map(str, VERSION))
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  """
3
2
  The :py:mod:`nameparser.config` module manages the configuration of the
4
3
  nameparser.
@@ -11,7 +10,7 @@ configuration by importing this instance and changing it.
11
10
 
12
11
  >>> from nameparser.config import CONSTANTS
13
12
  >>> CONSTANTS.titles.remove('hon').add('chemistry','dean') # doctest: +ELLIPSIS
14
- SetManager(set([u'msgt', ..., u'adjutant']))
13
+ SetManager({'msgt', ..., 'adjutant'})
15
14
 
16
15
  You can also adjust the configuration of individual instances by passing
17
16
  ``None`` as the second argument upon instantiation.
@@ -21,22 +20,23 @@ You can also adjust the configuration of individual instances by passing
21
20
  >>> from nameparser import HumanName
22
21
  >>> hn = HumanName("Dean Robert Johns", None)
23
22
  >>> hn.C.titles.add('dean') # doctest: +ELLIPSIS
24
- SetManager(set([u'msgt', ..., u'adjutant']))
23
+ SetManager({'msgt', ..., 'adjutant'})
25
24
  >>> hn.parse_full_name() # need to run this again after config changes
26
25
 
27
26
  **Potential Gotcha**: If you do not pass ``None`` as the second argument,
28
27
  ``hn.C`` will be a reference to the module config, possibly yielding
29
28
  unexpected results. See `Customizing the Parser <customize.html>`_.
30
29
  """
31
- from __future__ import unicode_literals
30
+ import re
32
31
  import sys
33
- try:
34
- # Python 3.3+
35
- from collections.abc import Set
36
- except ImportError:
37
- from collections import Set
32
+ from collections.abc import Iterable, Iterator, Mapping, Set
33
+ from typing import Any, TypeVar
34
+
35
+ if sys.version_info >= (3, 11):
36
+ from typing import Self
37
+ else:
38
+ from typing_extensions import Self
38
39
 
39
- from nameparser.util import binary_type
40
40
  from nameparser.util import lc
41
41
  from nameparser.config.prefixes import PREFIXES
42
42
  from nameparser.config.capitalization import CAPITALIZATION_EXCEPTIONS
@@ -45,7 +45,7 @@ from nameparser.config.suffixes import SUFFIX_ACRONYMS
45
45
  from nameparser.config.suffixes import SUFFIX_NOT_ACRONYMS
46
46
  from nameparser.config.titles import TITLES
47
47
  from nameparser.config.titles import FIRST_NAME_TITLES
48
- from nameparser.config.regexes import REGEXES
48
+ from nameparser.config.regexes import EMPTY_REGEX, REGEXES
49
49
 
50
50
  DEFAULT_ENCODING = 'UTF-8'
51
51
 
@@ -62,37 +62,25 @@ class SetManager(Set):
62
62
 
63
63
  '''
64
64
 
65
- def __init__(self, elements):
65
+ def __init__(self, elements: Iterable[str]) -> None:
66
66
  self.elements = set(elements)
67
67
 
68
- def __call__(self):
68
+ def __call__(self) -> Set[str]:
69
69
  return self.elements
70
70
 
71
- def __repr__(self):
71
+ def __repr__(self) -> str:
72
72
  return "SetManager({})".format(self.elements) # used for docs
73
73
 
74
- def __iter__(self):
74
+ def __iter__(self) -> Iterator[str]:
75
75
  return iter(self.elements)
76
76
 
77
- def __contains__(self, value):
77
+ def __contains__(self, value: object) -> bool:
78
78
  return value in self.elements
79
79
 
80
- def __len__(self):
80
+ def __len__(self) -> int:
81
81
  return len(self.elements)
82
82
 
83
- def next(self):
84
- return self.__next__()
85
-
86
- def __next__(self):
87
- if self.count >= len(self.elements):
88
- self.count = 0
89
- raise StopIteration
90
- else:
91
- c = self.count
92
- self.count = c + 1
93
- return getattr(self, self.elements[c]) or next(self)
94
-
95
- def add_with_encoding(self, s, encoding=None):
83
+ def add_with_encoding(self, s: str, encoding: str | None = None) -> None:
96
84
  """
97
85
  Add the lower case and no-period version of the string to the set. Pass an
98
86
  explicit `encoding` parameter to specify the encoding of binary strings that
@@ -102,49 +90,63 @@ class SetManager(Set):
102
90
  if sys.stdin:
103
91
  stdin_encoding = sys.stdin.encoding
104
92
  encoding = encoding or stdin_encoding or DEFAULT_ENCODING
105
- if type(s) == binary_type:
93
+ if isinstance(s, bytes):
106
94
  s = s.decode(encoding)
107
95
  self.elements.add(lc(s))
108
96
 
109
- def add(self, *strings):
97
+ def add(self, *strings: str) -> Self:
110
98
  """
111
99
  Add the lower case and no-period version of the string arguments to the set.
112
100
  Can pass a list of strings. Returns ``self`` for chaining.
113
101
  """
114
- [self.add_with_encoding(s) for s in strings]
102
+ for s in strings:
103
+ self.add_with_encoding(s)
104
+
115
105
  return self
116
106
 
117
- def remove(self, *strings):
107
+ def remove(self, *strings: str) -> Self:
118
108
  """
119
109
  Remove the lower case and no-period version of the string arguments from the set.
120
110
  Returns ``self`` for chaining.
121
111
  """
122
- [self.elements.remove(lc(s)) for s in strings if lc(s) in self.elements]
112
+ for s in strings:
113
+ if (lower := lc(s)) in self.elements:
114
+ self.elements.remove(lower)
115
+
123
116
  return self
124
117
 
125
118
 
126
- class TupleManager(dict):
119
+ T = TypeVar('T')
120
+
121
+
122
+ class TupleManager(dict[str, T]):
127
123
  '''
128
124
  A dictionary with dot.notation access. Subclass of ``dict``. Makes the tuple constants
129
125
  more friendly.
130
126
  '''
131
127
 
132
- def __getattr__(self, attr):
128
+ def __getattr__(self, attr: str) -> T | None:
133
129
  return self.get(attr)
130
+
134
131
  __setattr__ = dict.__setitem__
135
132
  __delattr__ = dict.__delitem__
136
133
 
137
- def __getstate__(self):
134
+ def __getstate__(self) -> Mapping[str, T]:
138
135
  return dict(self)
139
136
 
140
- def __setstate__(self, state):
141
- self.__init__(state)
137
+ def __setstate__(self, state: Mapping[str, T]) -> None:
138
+ self.update(state)
142
139
 
143
- def __reduce__(self):
140
+ def __reduce__(self) -> tuple[type, tuple[()], Mapping[str, T]]:
144
141
  return (TupleManager, (), self.__getstate__())
145
142
 
146
143
 
147
- class Constants(object):
144
+ class RegexTupleManager(TupleManager[re.Pattern[str]]):
145
+ def __getattr__(self, attr: str) -> re.Pattern[str]:
146
+ return self.get(attr, EMPTY_REGEX)
147
+
148
+
149
+ class Constants:
148
150
  """
149
151
  An instance of this class hold all of the configuration constants for the parser.
150
152
 
@@ -168,6 +170,17 @@ class Constants(object):
168
170
  :py:attr:`regexes` wrapped with :py:class:`TupleManager`.
169
171
  """
170
172
 
173
+ prefixes: SetManager
174
+ suffix_acronyms: SetManager
175
+ suffix_not_acronyms: SetManager
176
+ titles: SetManager
177
+ first_name_titles: SetManager
178
+ conjunctions: SetManager
179
+ capitalization_exceptions: TupleManager[str]
180
+ regexes: RegexTupleManager
181
+
182
+ _pst: Set[str] | None
183
+
171
184
  string_format = "{title} {first} {middle} {last} {suffix} ({nickname})"
172
185
  """
173
186
  The default string format use for all new `HumanName` instances.
@@ -187,9 +200,9 @@ class Constants(object):
187
200
  empty_attribute_default = ''
188
201
  """
189
202
  Default return value for empty attributes.
190
-
203
+
191
204
  .. doctest::
192
-
205
+
193
206
  >>> from nameparser.config import CONSTANTS
194
207
  >>> CONSTANTS.empty_attribute_default = None
195
208
  >>> name = HumanName("John Doe")
@@ -197,7 +210,7 @@ class Constants(object):
197
210
  None
198
211
  >>>name.first
199
212
  'John'
200
-
213
+
201
214
  """
202
215
 
203
216
  capitalize_name = False
@@ -232,15 +245,15 @@ class Constants(object):
232
245
  """
233
246
 
234
247
  def __init__(self,
235
- prefixes=PREFIXES,
236
- suffix_acronyms=SUFFIX_ACRONYMS,
237
- suffix_not_acronyms=SUFFIX_NOT_ACRONYMS,
238
- titles=TITLES,
239
- first_name_titles=FIRST_NAME_TITLES,
240
- conjunctions=CONJUNCTIONS,
241
- capitalization_exceptions=CAPITALIZATION_EXCEPTIONS,
242
- regexes=REGEXES
243
- ):
248
+ prefixes: Iterable[str] = PREFIXES,
249
+ suffix_acronyms: Iterable[str] = SUFFIX_ACRONYMS,
250
+ suffix_not_acronyms: Iterable[str] = SUFFIX_NOT_ACRONYMS,
251
+ titles: Iterable[str] = TITLES,
252
+ first_name_titles: Iterable[str] = FIRST_NAME_TITLES,
253
+ conjunctions: Iterable[str] = CONJUNCTIONS,
254
+ capitalization_exceptions: TupleManager[str] | Iterable[tuple[str, str]] = CAPITALIZATION_EXCEPTIONS,
255
+ regexes: RegexTupleManager | TupleManager[re.Pattern[str]] | Iterable[tuple[str, re.Pattern[str]]] = REGEXES
256
+ ) -> None:
244
257
  self.prefixes = SetManager(prefixes)
245
258
  self.suffix_acronyms = SetManager(suffix_acronyms)
246
259
  self.suffix_not_acronyms = SetManager(suffix_not_acronyms)
@@ -248,22 +261,22 @@ class Constants(object):
248
261
  self.first_name_titles = SetManager(first_name_titles)
249
262
  self.conjunctions = SetManager(conjunctions)
250
263
  self.capitalization_exceptions = TupleManager(capitalization_exceptions)
251
- self.regexes = TupleManager(regexes)
264
+ self.regexes = RegexTupleManager(regexes)
252
265
  self._pst = None
253
266
 
254
267
  @property
255
- def suffixes_prefixes_titles(self):
268
+ def suffixes_prefixes_titles(self) -> Set[str]:
256
269
  if not self._pst:
257
270
  self._pst = self.prefixes | self.suffix_acronyms | self.suffix_not_acronyms | self.titles
258
271
  return self._pst
259
272
 
260
- def __repr__(self):
273
+ def __repr__(self) -> str:
261
274
  return "<Constants() instance>"
262
275
 
263
- def __setstate__(self, state):
264
- self.__init__(state)
276
+ def __setstate__(self, state: Mapping[str, Any]) -> None:
277
+ Constants.__init__(self, state)
265
278
 
266
- def __getstate__(self):
279
+ def __getstate__(self) -> Mapping[str, Any]:
267
280
  attrs = [x for x in dir(self) if not x.startswith('_')]
268
281
  return dict([(a, getattr(self, a)) for a in attrs])
269
282
 
@@ -1,6 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
1
  CAPITALIZATION_EXCEPTIONS = (
5
2
  ('ii', 'II'),
6
3
  ('iii', 'III'),
@@ -10,4 +7,4 @@ CAPITALIZATION_EXCEPTIONS = (
10
7
  )
11
8
  """
12
9
  Any pieces that are not capitalized by capitalizing the first letter.
13
- """
10
+ """
@@ -1,6 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
1
  CONJUNCTIONS = set([
5
2
  '&',
6
3
  'and',
@@ -15,4 +12,4 @@ CONJUNCTIONS = set([
15
12
  Pieces that should join to their neighboring pieces, e.g. "and", "y" and "&".
16
13
  "of" and "the" are also include to facilitate joining multiple titles,
17
14
  e.g. "President of the United States".
18
- """
15
+ """
@@ -1,6 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
1
  #: Name pieces that appear before a last name. Prefixes join to the piece
5
2
  #: that follows them to make one new piece. They can be chained together, e.g
6
3
  #: "von der" and "de la". Because they only appear in middle or last names,
@@ -1,22 +1,13 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
1
  import re
4
2
 
5
3
  # emoji regex from https://stackoverflow.com/questions/26568722/remove-unicode-emoji-using-re-in-python
6
- try:
7
- # Wide UCS-4 build
8
- re_emoji = re.compile('['
9
- '\U0001F300-\U0001F64F'
10
- '\U0001F680-\U0001F6FF'
11
- '\u2600-\u26FF\u2700-\u27BF]+',
12
- re.UNICODE)
13
- except re.error:
14
- # Narrow UCS-2 build
15
- re_emoji = re.compile('('
16
- '\ud83c[\udf00-\udfff]|'
17
- '\ud83d[\udc00-\ude4f\ude80-\udeff]|'
18
- '[\u2600-\u26FF\u2700-\u27BF])+',
19
- re.UNICODE)
4
+ re_emoji = re.compile('[' # lgtm[py/overly-large-range]
5
+ '\U0001F300-\U0001F64F'
6
+ '\U0001F680-\U0001F6FF'
7
+ '\u2600-\u26FF\u2700-\u27BF]+',
8
+ re.UNICODE)
9
+
10
+ EMPTY_REGEX = re.compile('')
20
11
 
21
12
  REGEXES = set([
22
13
  ("spaces", re.compile(r"\s+", re.U)),
@@ -1,6 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
1
  SUFFIX_NOT_ACRONYMS = set([
5
2
  'dr',
6
3
  'esq',
@@ -1,6 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
- from __future__ import unicode_literals
3
-
4
1
  FIRST_NAME_TITLES = set([
5
2
  'aunt',
6
3
  'auntie',