pyannote.database 5.0.0__tar.gz → 5.1.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 (33) hide show
  1. {pyannote.database-5.0.0/pyannote.database.egg-info → pyannote.database-5.1.0}/PKG-INFO +4 -5
  2. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/_version.py +2 -2
  3. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/custom.py +18 -5
  4. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/registry.py +50 -35
  5. {pyannote.database-5.0.0 → pyannote.database-5.1.0/pyannote.database.egg-info}/PKG-INFO +4 -5
  6. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/requires.txt +1 -1
  7. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/setup.py +7 -6
  8. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/versioneer.py +135 -85
  9. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/LICENSE +0 -0
  10. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/MANIFEST.in +0 -0
  11. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/README.md +0 -0
  12. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/__init__.py +0 -0
  13. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/__init__.py +0 -0
  14. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/cli.py +0 -0
  15. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/database.py +0 -0
  16. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/file_finder.py +0 -0
  17. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/loader.py +0 -0
  18. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/__init__.py +0 -0
  19. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/collection.py +0 -0
  20. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/protocol.py +0 -0
  21. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/segmentation.py +0 -0
  22. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/speaker_diarization.py +0 -0
  23. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/speaker_identification.py +0 -0
  24. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/speaker_recognition.py +0 -0
  25. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/speaker_spotting.py +0 -0
  26. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/protocol/speaker_verification.py +0 -0
  27. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote/database/util.py +0 -0
  28. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/SOURCES.txt +0 -0
  29. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/dependency_links.txt +0 -0
  30. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/entry_points.txt +0 -0
  31. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/namespace_packages.txt +0 -0
  32. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/pyannote.database.egg-info/top_level.txt +0 -0
  33. {pyannote.database-5.0.0 → pyannote.database-5.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyannote.database
3
- Version: 5.0.0
3
+ Version: 5.1.0
4
4
  Summary: Interface to multimedia databases and experimental protocols
5
5
  Home-page: http://pyannote.github.io/
6
6
  Author: Hervé Bredin
@@ -9,10 +9,9 @@ Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Intended Audience :: Science/Research
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Natural Language :: English
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.6
14
- Classifier: Programming Language :: Python :: 3.7
15
- Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Topic :: Scientific/Engineering
17
16
  Provides-Extra: testing
18
17
  Provides-Extra: doc
@@ -11,8 +11,8 @@ version_json = '''
11
11
  {
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "d8f589d27d41cad27d25510e3d6c051ed79b68c7",
15
- "version": "5.0.0"
14
+ "full-revisionid": "b1fc3492e7ea8aa822f1c0993fcd38c485a6b61e",
15
+ "version": "5.1.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -51,6 +51,7 @@ from . import protocol as protocol_module
51
51
  from pyannote.database.protocol.protocol import ProtocolFile
52
52
  import yaml
53
53
  import warnings
54
+ from numbers import Number
54
55
  from typing import Text, Dict, Callable, Any, Union
55
56
  import functools
56
57
 
@@ -115,6 +116,12 @@ def Template(template: Text, database_yml: Path) -> Callable[[ProtocolFile], Any
115
116
  return load
116
117
 
117
118
 
119
+ def NumericValue(value):
120
+ def load(current_file: ProtocolFile):
121
+ return value
122
+ return load
123
+
124
+
118
125
  def resolve_path(path: Path, database_yml: Path) -> Path:
119
126
  """Resolve path
120
127
 
@@ -211,6 +218,10 @@ def gather_loaders(
211
218
  if key == "uri" or key == "trial":
212
219
  continue
213
220
 
221
+ if isinstance(value, Number):
222
+ lazy_loader[key] = NumericValue(value)
223
+ continue
224
+
214
225
  # check whether value (path) contains placeholders such as {uri} or {subset}
215
226
  _, placeholders, _, _ = zip(*string.Formatter().parse(value))
216
227
  is_template = len(set(placeholders) - set([None])) > 0
@@ -442,16 +453,18 @@ def create_protocol(
442
453
  metadata["classes"] = protocol_entries.pop("classes")
443
454
 
444
455
  if issubclass(base_class, SpeakerDiarizationProtocol):
445
- if "scope" in protocol_entries:
446
- scope = protocol_entries.pop("scope")
447
- else:
448
- scope = "file"
456
+ scope = protocol_entries.pop("scope", None)
457
+
458
+ if scope is None and database != "X":
449
459
  msg = (
450
460
  f"'{database}.{task}.{protocol}' found in {database_yml} does not define "
451
461
  f"the 'scope' of speaker labels (file, database, or global). Setting it to 'file'."
452
462
  )
453
463
  print(msg)
454
- metadata["scope"] = scope
464
+ metadata["scope"] = "file"
465
+
466
+ else:
467
+ metadata["scope"] = scope
455
468
 
456
469
  methods = dict()
457
470
  for subset, subset_entries in protocol_entries.items():
@@ -39,11 +39,13 @@ from .custom import create_protocol, get_init
39
39
  from .database import Database
40
40
  import yaml
41
41
 
42
+
42
43
  # controls what to do in case of protocol name conflict
43
44
  class LoadingMode(Enum):
44
45
  OVERRIDE = 0 # override existing protocol
45
- KEEP = 1 # keep existing protocol
46
- ERROR = 2 # raise an error
46
+ KEEP = 1 # keep existing protocol
47
+ ERROR = 2 # raise an error
48
+
47
49
 
48
50
  # To ease the understanding of future me, all comments inside Registry codebase
49
51
  # assume the existence of the following database.yml files.
@@ -52,7 +54,7 @@ class LoadingMode(Enum):
52
54
  # Content of /path/to/first/database.yml
53
55
  # ======================================
54
56
  # Databases:
55
- # DatabaseA:
57
+ # DatabaseA:
56
58
  # - relative/path/A/trn/{uri}.wav
57
59
  # - relative/path/A/dev/{uri}.wav
58
60
  # - relative/path/A/tst/{uri}.wav
@@ -95,7 +97,7 @@ class LoadingMode(Enum):
95
97
  # DatabaseC:
96
98
  # SpeakerDiarization:
97
99
  # Protocol:
98
- # ...
100
+ # ...
99
101
 
100
102
 
101
103
  class Registry:
@@ -109,13 +111,12 @@ class Registry:
109
111
  """
110
112
 
111
113
  def __init__(self) -> None:
112
-
113
114
  # Mapping of database.yml paths to their config in a dictionary
114
115
  # Example after loading both database.yml:
115
116
  # {"/path/to/first/database.yml": {
116
117
  # "Databases":{
117
118
  # "DatabaseA": ["relative/path/A/trn/{uri}.wav", "relative/path/A/dev/{uri}.wav", relative/path/A/tst/{uri}.wav]
118
- # "DatabaseB": "/absolute/path/B/{uri}.wav"
119
+ # "DatabaseB": "/absolute/path/B/{uri}.wav"
119
120
  # },
120
121
  # "Protocols":{
121
122
  # "DatabaseA":{
@@ -134,7 +135,7 @@ class Registry:
134
135
  # "/path/to/second/database.yml": {
135
136
  # "Databases":{
136
137
  # "DatabaseC": /absolute/path/C/{uri}.wav
137
- # "DatabaseB": "/absolute/path/B/{uri}.wav"
138
+ # "DatabaseB": "/absolute/path/B/{uri}.wav"
138
139
  # },
139
140
  # "Protocols":{
140
141
  # "DatabaseB":{"SpeakerDiarization": {"Protocol": {...}}},
@@ -144,7 +145,6 @@ class Registry:
144
145
  # }
145
146
  self.configs: Dict[Path, Dict] = dict()
146
147
 
147
-
148
148
  # Content of the "Database" root item (= where to find file content)
149
149
  # Example after loading both database.yml:
150
150
  # {
@@ -176,7 +176,7 @@ class Registry:
176
176
  Parameters
177
177
  ----------
178
178
  path : str or Path
179
- Path to YAML configuration file.
179
+ Path to YAML configuration file.
180
180
  mode : LoadingMode, optional
181
181
  Controls how to handle conflicts in protocol names.
182
182
  Defaults to overriding the existing protocol.
@@ -210,7 +210,7 @@ class Registry:
210
210
  # make path absolute
211
211
  database_yml = Path(database_yml).expanduser().resolve()
212
212
 
213
- # stop here if configuration file is already being loaded
213
+ # stop here if configuration file is already being loaded
214
214
  # (possibly because of circular requirements)
215
215
  if database_yml in loading:
216
216
  return
@@ -221,9 +221,9 @@ class Registry:
221
221
  # load configuration
222
222
  with open(database_yml, "r") as f:
223
223
  config = yaml.load(f, Loader=yaml.SafeLoader)
224
-
224
+
225
225
  # load every requirement
226
- requirements = config.pop('Requirements', list())
226
+ requirements = config.pop("Requirements", list())
227
227
  if not isinstance(requirements, list):
228
228
  requirements = [requirements]
229
229
  for requirement_yaml in requirements:
@@ -244,9 +244,7 @@ class Registry:
244
244
 
245
245
  # load protocols of each database
246
246
  for db_name, db_entries in protocols.items():
247
- self._load_protocols(
248
- db_name, db_entries, database_yml, mode=mode
249
- )
247
+ self._load_protocols(db_name, db_entries, database_yml, mode=mode)
250
248
 
251
249
  # process "Databases" section
252
250
  databases = config.get("Databases", dict())
@@ -265,7 +263,6 @@ class Registry:
265
263
  # save configuration for later reloading of meta-protocols
266
264
  self.configs[database_yml] = config
267
265
 
268
-
269
266
  def get_database(self, database_name, **kwargs) -> Database:
270
267
  """Get database by name
271
268
 
@@ -284,7 +281,6 @@ class Registry:
284
281
  database = self.databases[database_name]
285
282
 
286
283
  except KeyError:
287
-
288
284
  if database_name == "X":
289
285
  msg = (
290
286
  "Could not find any meta-protocol. Please refer to "
@@ -302,7 +298,9 @@ class Registry:
302
298
 
303
299
  return database(**kwargs)
304
300
 
305
- def get_protocol(self, name, preprocessors: Optional[Preprocessors] = None) -> Protocol:
301
+ def get_protocol(
302
+ self, name, preprocessors: Optional[Preprocessors] = None
303
+ ) -> Protocol:
306
304
  """Get protocol by full name
307
305
 
308
306
  Parameters
@@ -329,6 +327,14 @@ class Registry:
329
327
  protocol.name = name
330
328
  return protocol
331
329
 
330
+ # iterate over all protocols by name
331
+ def __iter__(self):
332
+ for database_name in self.databases:
333
+ database = self.get_database(database_name)
334
+ for task_name in database.get_tasks():
335
+ for protocol_name in database.get_protocols(task_name):
336
+ yield f"{database_name}.{task_name}.{protocol_name}"
337
+
332
338
  def _load_protocols(
333
339
  self,
334
340
  db_name,
@@ -367,7 +373,9 @@ class Registry:
367
373
  # If needed, merge old protocols dict with the new one (according to current override rules)
368
374
  if db_name in self.databases:
369
375
  old_protocols = self.databases[db_name]._protocols
370
- _merge_protocols_inplace(protocols, old_protocols, mode, db_name, database_yml)
376
+ _merge_protocols_inplace(
377
+ protocols, old_protocols, mode, db_name, database_yml
378
+ )
371
379
 
372
380
  # create database class on-the-fly
373
381
  protocol_list = [
@@ -389,13 +397,14 @@ class Registry:
389
397
  for db_yml, config in self.configs.items():
390
398
  databases = config.get("Protocols", dict())
391
399
  if "X" in databases:
392
- self._load_protocols("X", databases["X"], db_yml, mode=LoadingMode.OVERRIDE)
393
-
400
+ self._load_protocols(
401
+ "X", databases["X"], db_yml, mode=LoadingMode.OVERRIDE
402
+ )
394
403
 
395
404
 
396
405
  def _env_config_paths() -> List[Path]:
397
406
  """Parse PYANNOTE_DATABASE_CONFIG environment variable
398
-
407
+
399
408
  PYANNOTE_DATABASE_CONFIG may contain multiple paths separation by ";".
400
409
 
401
410
  Returns
@@ -413,10 +422,11 @@ def _env_config_paths() -> List[Path]:
413
422
  paths.append(path)
414
423
  return paths
415
424
 
425
+
416
426
  def _find_default_ymls() -> List[Path]:
417
427
  """Get paths to default YAML configuration files
418
428
 
419
- * $HOME/.pyannote/database.yml
429
+ * $HOME/.pyannote/database.yml
420
430
  * $CWD/database.yml
421
431
  * PYANNOTE_DATABASE_CONFIG environment variable
422
432
 
@@ -431,21 +441,23 @@ def _find_default_ymls() -> List[Path]:
431
441
  home_db_yml = Path("~/.pyannote/database.yml").expanduser()
432
442
  if home_db_yml.is_file():
433
443
  paths.append(home_db_yml)
434
-
444
+
435
445
  cwd_db_yml = Path.cwd() / "database.yml"
436
446
  if cwd_db_yml.is_file():
437
447
  paths.append(cwd_db_yml)
438
-
448
+
439
449
  paths += _env_config_paths()
440
450
 
441
451
  return paths
442
452
 
453
+
443
454
  def _merge_protocols_inplace(
444
- new_protocols: Dict[Tuple[Text, Text], Type],
445
- old_protocols: Dict[Tuple[Text, Text], Type],
446
- mode: LoadingMode,
447
- db_name: str,
448
- database_yml: str):
455
+ new_protocols: Dict[Tuple[Text, Text], Type],
456
+ old_protocols: Dict[Tuple[Text, Text], Type],
457
+ mode: LoadingMode,
458
+ db_name: str,
459
+ database_yml: str,
460
+ ):
449
461
  """Merge new and old protocols inplace into the passed new_protocol.
450
462
 
451
463
  Warning, merging order might be counterintuitive : "KEEP" strategy keeps element from the OLD protocol
@@ -471,7 +483,6 @@ def _merge_protocols_inplace(
471
483
 
472
484
  # for all previously defined protocol (in old_protocols)
473
485
  for p_id, old_p in old_protocols.items():
474
-
475
486
  # if this protocol is redefined
476
487
  if p_id in new_protocols:
477
488
  t_name, p_name = p_id
@@ -480,13 +491,16 @@ def _merge_protocols_inplace(
480
491
  # raise an error
481
492
  if mode == LoadingMode.ERROR:
482
493
  raise RuntimeError(
483
- f"Cannot load {realname} protocol from '{database_yml}' as it already exists.")
494
+ f"Cannot load {realname} protocol from '{database_yml}' as it already exists."
495
+ )
484
496
 
485
497
  # keep the new protocol
486
498
  elif mode == LoadingMode.OVERRIDE:
487
- warnings.warn(f"Replacing existing {realname} protocol by the one defined in '{database_yml}'.")
499
+ warnings.warn(
500
+ f"Replacing existing {realname} protocol by the one defined in '{database_yml}'."
501
+ )
488
502
  pass
489
-
503
+
490
504
  # keep the old protocol
491
505
  elif mode == LoadingMode.KEEP:
492
506
  warnings.warn(
@@ -498,9 +512,10 @@ def _merge_protocols_inplace(
498
512
  else:
499
513
  new_protocols[p_id] = old_p
500
514
 
515
+
501
516
  # initialize the registry singleton
502
517
  registry = Registry()
503
518
 
504
519
  # load all database yaml files found at startup
505
520
  for yml in _find_default_ymls():
506
- registry.load_database(yml)
521
+ registry.load_database(yml)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyannote.database
3
- Version: 5.0.0
3
+ Version: 5.1.0
4
4
  Summary: Interface to multimedia databases and experimental protocols
5
5
  Home-page: http://pyannote.github.io/
6
6
  Author: Hervé Bredin
@@ -9,10 +9,9 @@ Classifier: Development Status :: 4 - Beta
9
9
  Classifier: Intended Audience :: Science/Research
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Natural Language :: English
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.6
14
- Classifier: Programming Language :: Python :: 3.7
15
- Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Topic :: Scientific/Engineering
17
16
  Provides-Extra: testing
18
17
  Provides-Extra: doc
@@ -1,7 +1,7 @@
1
1
  pyannote.core>=4.1
2
2
  pyYAML>=3.12
3
3
  pandas>=0.19
4
- typer[all]>=0.2.1
4
+ typer>=0.12.1
5
5
 
6
6
  [:python_version < "3.8"]
7
7
  typing_extensions>=3.7.4
@@ -37,11 +37,13 @@ setup(
37
37
  "pyannote.core >= 4.1",
38
38
  "pyYAML >= 3.12",
39
39
  "pandas >= 0.19",
40
- "typer[all] >= 0.2.1",
40
+ "typer >= 0.12.1",
41
41
  "typing_extensions >= 3.7.4;python_version < '3.8'",
42
42
  ],
43
43
  entry_points={
44
- "console_scripts": ["pyannote-database=pyannote.database.cli:main",],
44
+ "console_scripts": [
45
+ "pyannote-database=pyannote.database.cli:main",
46
+ ],
45
47
  "pyannote.database.loader": [
46
48
  ".rttm = pyannote.database.loader:RTTMLoader",
47
49
  ".uem = pyannote.database.loader:UEMLoader",
@@ -65,10 +67,9 @@ setup(
65
67
  "Intended Audience :: Science/Research",
66
68
  "License :: OSI Approved :: MIT License",
67
69
  "Natural Language :: English",
68
- "Programming Language :: Python :: 3",
69
- "Programming Language :: Python :: 3.6",
70
- "Programming Language :: Python :: 3.7",
71
- "Programming Language :: Python :: 3.8",
70
+ "Programming Language :: Python :: 3.9",
71
+ "Programming Language :: Python :: 3.10",
72
+ "Programming Language :: Python :: 3.11",
72
73
  "Topic :: Scientific/Engineering",
73
74
  ],
74
75
  extras_require={
@@ -1,4 +1,3 @@
1
-
2
1
  # Version: 0.15
3
2
 
4
3
  """
@@ -340,6 +339,7 @@ domain.
340
339
  """
341
340
 
342
341
  from __future__ import print_function
342
+
343
343
  try:
344
344
  import configparser
345
345
  except ImportError:
@@ -368,11 +368,13 @@ def get_root():
368
368
  setup_py = os.path.join(root, "setup.py")
369
369
  versioneer_py = os.path.join(root, "versioneer.py")
370
370
  if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)):
371
- err = ("Versioneer was unable to run the project root directory. "
372
- "Versioneer requires setup.py to be executed from "
373
- "its immediate directory (like 'python setup.py COMMAND'), "
374
- "or in a way that lets it use sys.argv[0] to find the root "
375
- "(like 'python path/to/setup.py COMMAND').")
371
+ err = (
372
+ "Versioneer was unable to run the project root directory. "
373
+ "Versioneer requires setup.py to be executed from "
374
+ "its immediate directory (like 'python setup.py COMMAND'), "
375
+ "or in a way that lets it use sys.argv[0] to find the root "
376
+ "(like 'python path/to/setup.py COMMAND')."
377
+ )
376
378
  raise VersioneerBadRootError(err)
377
379
  try:
378
380
  # Certain runtime workflows (setup.py install/develop in a setuptools
@@ -383,8 +385,10 @@ def get_root():
383
385
  # versioneer.py was first imported, even in later projects.
384
386
  me = os.path.realpath(os.path.abspath(__file__))
385
387
  if os.path.splitext(me)[0] != os.path.splitext(versioneer_py)[0]:
386
- print("Warning: build in %s is using versioneer.py from %s"
387
- % (os.path.dirname(me), versioneer_py))
388
+ print(
389
+ "Warning: build in %s is using versioneer.py from %s"
390
+ % (os.path.dirname(me), versioneer_py)
391
+ )
388
392
  except NameError:
389
393
  pass
390
394
  return root
@@ -396,15 +400,16 @@ def get_config_from_root(root):
396
400
  # configparser.NoOptionError (if it lacks "VCS="). See the docstring at
397
401
  # the top of versioneer.py for instructions on writing your setup.cfg .
398
402
  setup_cfg = os.path.join(root, "setup.cfg")
399
- parser = configparser.SafeConfigParser()
403
+ parser = configparser.ConfigParser()
400
404
  with open(setup_cfg, "r") as f:
401
- parser.readfp(f)
405
+ parser.read_file(f)
402
406
  VCS = parser.get("versioneer", "VCS") # mandatory
403
407
 
404
408
  def get(parser, name):
405
409
  if parser.has_option("versioneer", name):
406
410
  return parser.get("versioneer", name)
407
411
  return None
412
+
408
413
  cfg = VersioneerConfig()
409
414
  cfg.VCS = VCS
410
415
  cfg.style = get(parser, "style") or ""
@@ -419,6 +424,7 @@ def get_config_from_root(root):
419
424
  class NotThisMethod(Exception):
420
425
  pass
421
426
 
427
+
422
428
  # these dictionaries contain VCS-specific tools
423
429
  LONG_VERSION_PY = {}
424
430
  HANDLERS = {}
@@ -430,6 +436,7 @@ def register_vcs_handler(vcs, method): # decorator
430
436
  HANDLERS[vcs] = {}
431
437
  HANDLERS[vcs][method] = f
432
438
  return f
439
+
433
440
  return decorate
434
441
 
435
442
 
@@ -440,9 +447,12 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
440
447
  try:
441
448
  dispcmd = str([c] + args)
442
449
  # remember shell=False, so use git.cmd on windows, not just git
443
- p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
444
- stderr=(subprocess.PIPE if hide_stderr
445
- else None))
450
+ p = subprocess.Popen(
451
+ [c] + args,
452
+ cwd=cwd,
453
+ stdout=subprocess.PIPE,
454
+ stderr=(subprocess.PIPE if hide_stderr else None),
455
+ )
446
456
  break
447
457
  except EnvironmentError:
448
458
  e = sys.exc_info()[1]
@@ -464,7 +474,11 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
464
474
  print("unable to run %s (error)" % dispcmd)
465
475
  return None
466
476
  return stdout
467
- LONG_VERSION_PY['git'] = '''
477
+
478
+
479
+ LONG_VERSION_PY[
480
+ "git"
481
+ ] = """
468
482
  # This file helps to compute a version number in source trees obtained from
469
483
  # git-archive tarball (such as those provided by githubs download-from-tag
470
484
  # feature). Distribution tarballs (built by setup.py sdist) and build
@@ -924,7 +938,7 @@ def get_versions():
924
938
  return {"version": "0+unknown", "full-revisionid": None,
925
939
  "dirty": None,
926
940
  "error": "unable to compute version"}
927
- '''
941
+ """
928
942
 
929
943
 
930
944
  @register_vcs_handler("git", "get_keywords")
@@ -964,7 +978,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
964
978
  # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
965
979
  # just "foo-1.0". If we see a "tag: " prefix, prefer those.
966
980
  TAG = "tag: "
967
- tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
981
+ tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)])
968
982
  if not tags:
969
983
  # Either we're using git < 1.8.3, or there really are no tags. We use
970
984
  # a heuristic: assume all version tags have a digit. The old git %d
@@ -973,27 +987,32 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose):
973
987
  # between branches and tags. By ignoring refnames without digits, we
974
988
  # filter out many common branch names like "release" and
975
989
  # "stabilization", as well as "HEAD" and "master".
976
- tags = set([r for r in refs if re.search(r'\d', r)])
990
+ tags = set([r for r in refs if re.search(r"\d", r)])
977
991
  if verbose:
978
- print("discarding '%s', no digits" % ",".join(refs-tags))
992
+ print("discarding '%s', no digits" % ",".join(refs - tags))
979
993
  if verbose:
980
994
  print("likely tags: %s" % ",".join(sorted(tags)))
981
995
  for ref in sorted(tags):
982
996
  # sorting will prefer e.g. "2.0" over "2.0rc1"
983
997
  if ref.startswith(tag_prefix):
984
- r = ref[len(tag_prefix):]
998
+ r = ref[len(tag_prefix) :]
985
999
  if verbose:
986
1000
  print("picking %s" % r)
987
- return {"version": r,
988
- "full-revisionid": keywords["full"].strip(),
989
- "dirty": False, "error": None
990
- }
1001
+ return {
1002
+ "version": r,
1003
+ "full-revisionid": keywords["full"].strip(),
1004
+ "dirty": False,
1005
+ "error": None,
1006
+ }
991
1007
  # no suitable tags, so version is "0+unknown", but full hex is still there
992
1008
  if verbose:
993
1009
  print("no suitable tags, using unknown + full revision id")
994
- return {"version": "0+unknown",
995
- "full-revisionid": keywords["full"].strip(),
996
- "dirty": False, "error": "no suitable tags"}
1010
+ return {
1011
+ "version": "0+unknown",
1012
+ "full-revisionid": keywords["full"].strip(),
1013
+ "dirty": False,
1014
+ "error": "no suitable tags",
1015
+ }
997
1016
 
998
1017
 
999
1018
  @register_vcs_handler("git", "pieces_from_vcs")
@@ -1013,9 +1032,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1013
1032
  GITS = ["git.cmd", "git.exe"]
1014
1033
  # if there is a tag, this yields TAG-NUM-gHEX[-dirty]
1015
1034
  # if there are no tags, this yields HEX[-dirty] (no NUM)
1016
- describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
1017
- "--always", "--long"],
1018
- cwd=root)
1035
+ describe_out = run_command(
1036
+ GITS, ["describe", "--tags", "--dirty", "--always", "--long"], cwd=root
1037
+ )
1019
1038
  # --long was added in git-1.5.5
1020
1039
  if describe_out is None:
1021
1040
  raise NotThisMethod("'git describe' failed")
@@ -1038,17 +1057,16 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1038
1057
  dirty = git_describe.endswith("-dirty")
1039
1058
  pieces["dirty"] = dirty
1040
1059
  if dirty:
1041
- git_describe = git_describe[:git_describe.rindex("-dirty")]
1060
+ git_describe = git_describe[: git_describe.rindex("-dirty")]
1042
1061
 
1043
1062
  # now we have TAG-NUM-gHEX or HEX
1044
1063
 
1045
1064
  if "-" in git_describe:
1046
1065
  # TAG-NUM-gHEX
1047
- mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
1066
+ mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe)
1048
1067
  if not mo:
1049
1068
  # unparseable. Maybe git-describe is misbehaving?
1050
- pieces["error"] = ("unable to parse git-describe output: '%s'"
1051
- % describe_out)
1069
+ pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out
1052
1070
  return pieces
1053
1071
 
1054
1072
  # tag
@@ -1057,10 +1075,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1057
1075
  if verbose:
1058
1076
  fmt = "tag '%s' doesn't start with prefix '%s'"
1059
1077
  print(fmt % (full_tag, tag_prefix))
1060
- pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
1061
- % (full_tag, tag_prefix))
1078
+ pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % (
1079
+ full_tag,
1080
+ tag_prefix,
1081
+ )
1062
1082
  return pieces
1063
- pieces["closest-tag"] = full_tag[len(tag_prefix):]
1083
+ pieces["closest-tag"] = full_tag[len(tag_prefix) :]
1064
1084
 
1065
1085
  # distance: number of commits since tag
1066
1086
  pieces["distance"] = int(mo.group(2))
@@ -1071,8 +1091,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
1071
1091
  else:
1072
1092
  # HEX: no tags
1073
1093
  pieces["closest-tag"] = None
1074
- count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
1075
- cwd=root)
1094
+ count_out = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root)
1076
1095
  pieces["distance"] = int(count_out) # total number of commits
1077
1096
 
1078
1097
  return pieces
@@ -1117,12 +1136,18 @@ def versions_from_parentdir(parentdir_prefix, root, verbose):
1117
1136
  dirname = os.path.basename(root)
1118
1137
  if not dirname.startswith(parentdir_prefix):
1119
1138
  if verbose:
1120
- print("guessing rootdir is '%s', but '%s' doesn't start with "
1121
- "prefix '%s'" % (root, dirname, parentdir_prefix))
1139
+ print(
1140
+ "guessing rootdir is '%s', but '%s' doesn't start with "
1141
+ "prefix '%s'" % (root, dirname, parentdir_prefix)
1142
+ )
1122
1143
  raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
1123
- return {"version": dirname[len(parentdir_prefix):],
1124
- "full-revisionid": None,
1125
- "dirty": False, "error": None}
1144
+ return {
1145
+ "version": dirname[len(parentdir_prefix) :],
1146
+ "full-revisionid": None,
1147
+ "dirty": False,
1148
+ "error": None,
1149
+ }
1150
+
1126
1151
 
1127
1152
  SHORT_VERSION_PY = """
1128
1153
  # This file was generated by 'versioneer.py' (0.15) from
@@ -1149,8 +1174,9 @@ def versions_from_file(filename):
1149
1174
  contents = f.read()
1150
1175
  except EnvironmentError:
1151
1176
  raise NotThisMethod("unable to read _version.py")
1152
- mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON",
1153
- contents, re.M | re.S)
1177
+ mo = re.search(
1178
+ r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S
1179
+ )
1154
1180
  if not mo:
1155
1181
  raise NotThisMethod("no version_json in _version.py")
1156
1182
  return json.loads(mo.group(1))
@@ -1158,8 +1184,7 @@ def versions_from_file(filename):
1158
1184
 
1159
1185
  def write_to_version_file(filename, versions):
1160
1186
  os.unlink(filename)
1161
- contents = json.dumps(versions, sort_keys=True,
1162
- indent=1, separators=(",", ": "))
1187
+ contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": "))
1163
1188
  with open(filename, "w") as f:
1164
1189
  f.write(SHORT_VERSION_PY % contents)
1165
1190
 
@@ -1189,8 +1214,7 @@ def render_pep440(pieces):
1189
1214
  rendered += ".dirty"
1190
1215
  else:
1191
1216
  # exception #1
1192
- rendered = "0+untagged.%d.g%s" % (pieces["distance"],
1193
- pieces["short"])
1217
+ rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"])
1194
1218
  if pieces["dirty"]:
1195
1219
  rendered += ".dirty"
1196
1220
  return rendered
@@ -1297,10 +1321,12 @@ def render_git_describe_long(pieces):
1297
1321
 
1298
1322
  def render(pieces, style):
1299
1323
  if pieces["error"]:
1300
- return {"version": "unknown",
1301
- "full-revisionid": pieces.get("long"),
1302
- "dirty": None,
1303
- "error": pieces["error"]}
1324
+ return {
1325
+ "version": "unknown",
1326
+ "full-revisionid": pieces.get("long"),
1327
+ "dirty": None,
1328
+ "error": pieces["error"],
1329
+ }
1304
1330
 
1305
1331
  if not style or style == "default":
1306
1332
  style = "pep440" # the default
@@ -1320,8 +1346,12 @@ def render(pieces, style):
1320
1346
  else:
1321
1347
  raise ValueError("unknown style '%s'" % style)
1322
1348
 
1323
- return {"version": rendered, "full-revisionid": pieces["long"],
1324
- "dirty": pieces["dirty"], "error": None}
1349
+ return {
1350
+ "version": rendered,
1351
+ "full-revisionid": pieces["long"],
1352
+ "dirty": pieces["dirty"],
1353
+ "error": None,
1354
+ }
1325
1355
 
1326
1356
 
1327
1357
  class VersioneerBadRootError(Exception):
@@ -1342,8 +1372,9 @@ def get_versions(verbose=False):
1342
1372
  handlers = HANDLERS.get(cfg.VCS)
1343
1373
  assert handlers, "unrecognized VCS '%s'" % cfg.VCS
1344
1374
  verbose = verbose or cfg.verbose
1345
- assert cfg.versionfile_source is not None, \
1346
- "please set versioneer.versionfile_source"
1375
+ assert (
1376
+ cfg.versionfile_source is not None
1377
+ ), "please set versioneer.versionfile_source"
1347
1378
  assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix"
1348
1379
 
1349
1380
  versionfile_abs = os.path.join(root, cfg.versionfile_source)
@@ -1397,8 +1428,12 @@ def get_versions(verbose=False):
1397
1428
  if verbose:
1398
1429
  print("unable to compute version")
1399
1430
 
1400
- return {"version": "0+unknown", "full-revisionid": None,
1401
- "dirty": None, "error": "unable to compute version"}
1431
+ return {
1432
+ "version": "0+unknown",
1433
+ "full-revisionid": None,
1434
+ "dirty": None,
1435
+ "error": "unable to compute version",
1436
+ }
1402
1437
 
1403
1438
 
1404
1439
  def get_version():
@@ -1444,6 +1479,7 @@ def get_cmdclass():
1444
1479
  print(" dirty: %s" % vers.get("dirty"))
1445
1480
  if vers["error"]:
1446
1481
  print(" error: %s" % vers["error"])
1482
+
1447
1483
  cmds["version"] = cmd_version
1448
1484
 
1449
1485
  # we override "build_py" in both distutils and setuptools
@@ -1467,10 +1503,10 @@ def get_cmdclass():
1467
1503
  # now locate _version.py in the new build/ directory and replace
1468
1504
  # it with an updated value
1469
1505
  if cfg.versionfile_build:
1470
- target_versionfile = os.path.join(self.build_lib,
1471
- cfg.versionfile_build)
1506
+ target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build)
1472
1507
  print("UPDATING %s" % target_versionfile)
1473
1508
  write_to_version_file(target_versionfile, versions)
1509
+
1474
1510
  cmds["build_py"] = cmd_build_py
1475
1511
 
1476
1512
  if "cx_Freeze" in sys.modules: # cx_freeze enabled?
@@ -1489,13 +1525,17 @@ def get_cmdclass():
1489
1525
  os.unlink(target_versionfile)
1490
1526
  with open(cfg.versionfile_source, "w") as f:
1491
1527
  LONG = LONG_VERSION_PY[cfg.VCS]
1492
- f.write(LONG %
1493
- {"DOLLAR": "$",
1494
- "STYLE": cfg.style,
1495
- "TAG_PREFIX": cfg.tag_prefix,
1496
- "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1497
- "VERSIONFILE_SOURCE": cfg.versionfile_source,
1498
- })
1528
+ f.write(
1529
+ LONG
1530
+ % {
1531
+ "DOLLAR": "$",
1532
+ "STYLE": cfg.style,
1533
+ "TAG_PREFIX": cfg.tag_prefix,
1534
+ "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1535
+ "VERSIONFILE_SOURCE": cfg.versionfile_source,
1536
+ }
1537
+ )
1538
+
1499
1539
  cmds["build_exe"] = cmd_build_exe
1500
1540
  del cmds["build_py"]
1501
1541
 
@@ -1523,8 +1563,10 @@ def get_cmdclass():
1523
1563
  # updated value
1524
1564
  target_versionfile = os.path.join(base_dir, cfg.versionfile_source)
1525
1565
  print("UPDATING %s" % target_versionfile)
1526
- write_to_version_file(target_versionfile,
1527
- self._versioneer_generated_versions)
1566
+ write_to_version_file(
1567
+ target_versionfile, self._versioneer_generated_versions
1568
+ )
1569
+
1528
1570
  cmds["sdist"] = cmd_sdist
1529
1571
 
1530
1572
  return cmds
@@ -1578,11 +1620,13 @@ def do_setup():
1578
1620
  root = get_root()
1579
1621
  try:
1580
1622
  cfg = get_config_from_root(root)
1581
- except (EnvironmentError, configparser.NoSectionError,
1582
- configparser.NoOptionError) as e:
1623
+ except (
1624
+ EnvironmentError,
1625
+ configparser.NoSectionError,
1626
+ configparser.NoOptionError,
1627
+ ) as e:
1583
1628
  if isinstance(e, (EnvironmentError, configparser.NoSectionError)):
1584
- print("Adding sample versioneer config to setup.cfg",
1585
- file=sys.stderr)
1629
+ print("Adding sample versioneer config to setup.cfg", file=sys.stderr)
1586
1630
  with open(os.path.join(root, "setup.cfg"), "a") as f:
1587
1631
  f.write(SAMPLE_CONFIG)
1588
1632
  print(CONFIG_ERROR, file=sys.stderr)
@@ -1591,15 +1635,18 @@ def do_setup():
1591
1635
  print(" creating %s" % cfg.versionfile_source)
1592
1636
  with open(cfg.versionfile_source, "w") as f:
1593
1637
  LONG = LONG_VERSION_PY[cfg.VCS]
1594
- f.write(LONG % {"DOLLAR": "$",
1595
- "STYLE": cfg.style,
1596
- "TAG_PREFIX": cfg.tag_prefix,
1597
- "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1598
- "VERSIONFILE_SOURCE": cfg.versionfile_source,
1599
- })
1600
-
1601
- ipy = os.path.join(os.path.dirname(cfg.versionfile_source),
1602
- "__init__.py")
1638
+ f.write(
1639
+ LONG
1640
+ % {
1641
+ "DOLLAR": "$",
1642
+ "STYLE": cfg.style,
1643
+ "TAG_PREFIX": cfg.tag_prefix,
1644
+ "PARENTDIR_PREFIX": cfg.parentdir_prefix,
1645
+ "VERSIONFILE_SOURCE": cfg.versionfile_source,
1646
+ }
1647
+ )
1648
+
1649
+ ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py")
1603
1650
  if os.path.exists(ipy):
1604
1651
  try:
1605
1652
  with open(ipy, "r") as f:
@@ -1641,8 +1688,10 @@ def do_setup():
1641
1688
  else:
1642
1689
  print(" 'versioneer.py' already in MANIFEST.in")
1643
1690
  if cfg.versionfile_source not in simple_includes:
1644
- print(" appending versionfile_source ('%s') to MANIFEST.in" %
1645
- cfg.versionfile_source)
1691
+ print(
1692
+ " appending versionfile_source ('%s') to MANIFEST.in"
1693
+ % cfg.versionfile_source
1694
+ )
1646
1695
  with open(manifest_in, "a") as f:
1647
1696
  f.write("include %s\n" % cfg.versionfile_source)
1648
1697
  else:
@@ -1690,6 +1739,7 @@ def scan_setup_py():
1690
1739
  errors += 1
1691
1740
  return errors
1692
1741
 
1742
+
1693
1743
  if __name__ == "__main__":
1694
1744
  cmd = sys.argv[1]
1695
1745
  if cmd == "setup":