1
1
import io
2
+ import os
2
3
import re
3
4
import abc
4
5
import csv
5
6
import sys
6
7
import email
7
8
import pathlib
9
+ import zipfile
8
10
import operator
9
11
import functools
10
12
import itertools
@@ -363,6 +365,58 @@ def find_distributions(self, context=Context()):
363
365
"""
364
366
365
367
368
+ class MetadataPathFinder (DistributionFinder ):
369
+ @classmethod
370
+ def find_distributions (cls , context = DistributionFinder .Context ()):
371
+ """
372
+ Find distributions.
373
+
374
+ Return an iterable of all Distribution instances capable of
375
+ loading the metadata for packages matching ``context.name``
376
+ (or all names if ``None`` indicated) along the paths in the list
377
+ of directories ``context.path``.
378
+ """
379
+ found = cls ._search_paths (context .pattern , context .path )
380
+ return map (PathDistribution , found )
381
+
382
+ @classmethod
383
+ def _search_paths (cls , pattern , paths ):
384
+ """Find metadata directories in paths heuristically."""
385
+ return itertools .chain .from_iterable (
386
+ cls ._search_path (path , pattern )
387
+ for path in map (cls ._switch_path , paths )
388
+ )
389
+
390
+ @staticmethod
391
+ def _switch_path (path ):
392
+ PYPY_OPEN_BUG = False
393
+ if not PYPY_OPEN_BUG or os .path .isfile (path ): # pragma: no branch
394
+ with suppress (Exception ):
395
+ return zipfile .Path (path )
396
+ return pathlib .Path (path )
397
+
398
+ @classmethod
399
+ def _matches_info (cls , normalized , item ):
400
+ template = r'{pattern}(-.*)?\.(dist|egg)-info'
401
+ manifest = template .format (pattern = normalized )
402
+ return re .match (manifest , item .name , flags = re .IGNORECASE )
403
+
404
+ @classmethod
405
+ def _matches_legacy (cls , normalized , item ):
406
+ template = r'{pattern}-.*\.egg[\\/]EGG-INFO'
407
+ manifest = template .format (pattern = normalized )
408
+ return re .search (manifest , str (item ), flags = re .IGNORECASE )
409
+
410
+ @classmethod
411
+ def _search_path (cls , root , pattern ):
412
+ if not root .is_dir ():
413
+ return ()
414
+ normalized = pattern .replace ('-' , '_' )
415
+ return (item for item in root .iterdir ()
416
+ if cls ._matches_info (normalized , item )
417
+ or cls ._matches_legacy (normalized , item ))
418
+
419
+
366
420
class PathDistribution (Distribution ):
367
421
def __init__ (self , path ):
368
422
"""Construct a distribution from a path to the metadata directory.
@@ -382,13 +436,13 @@ def locate_file(self, path):
382
436
return self ._path .parent / path
383
437
384
438
385
- def distribution (package ):
386
- """Get the ``Distribution`` instance for the given package.
439
+ def distribution (distribution_name ):
440
+ """Get the ``Distribution`` instance for the named package.
387
441
388
- :param package : The name of the package as a string.
442
+ :param distribution_name : The name of the distribution package as a string.
389
443
:return: A ``Distribution`` instance (or subclass thereof).
390
444
"""
391
- return Distribution .from_name (package )
445
+ return Distribution .from_name (distribution_name )
392
446
393
447
394
448
def distributions (** kwargs ):
@@ -399,23 +453,23 @@ def distributions(**kwargs):
399
453
return Distribution .discover (** kwargs )
400
454
401
455
402
- def metadata (package ):
403
- """Get the metadata for the package.
456
+ def metadata (distribution_name ):
457
+ """Get the metadata for the named package.
404
458
405
- :param package : The name of the distribution package to query.
459
+ :param distribution_name : The name of the distribution package to query.
406
460
:return: An email.Message containing the parsed metadata.
407
461
"""
408
- return Distribution .from_name (package ).metadata
462
+ return Distribution .from_name (distribution_name ).metadata
409
463
410
464
411
- def version (package ):
465
+ def version (distribution_name ):
412
466
"""Get the version string for the named package.
413
467
414
- :param package : The name of the distribution package to query.
468
+ :param distribution_name : The name of the distribution package to query.
415
469
:return: The version string for the package as defined in the package's
416
470
"Version" metadata key.
417
471
"""
418
- return distribution (package ).version
472
+ return distribution (distribution_name ).version
419
473
420
474
421
475
def entry_points ():
@@ -434,15 +488,20 @@ def entry_points():
434
488
}
435
489
436
490
437
- def files (package ):
438
- return distribution (package ).files
491
+ def files (distribution_name ):
492
+ """Return a list of files for the named package.
493
+
494
+ :param distribution_name: The name of the distribution package to query.
495
+ :return: List of files composing the distribution.
496
+ """
497
+ return distribution (distribution_name ).files
439
498
440
499
441
- def requires (package ):
500
+ def requires (distribution_name ):
442
501
"""
443
- Return a list of requirements for the indicated distribution .
502
+ Return a list of requirements for the named package .
444
503
445
504
:return: An iterator of requirements, suitable for
446
505
packaging.requirement.Requirement.
447
506
"""
448
- return distribution (package ).requires
507
+ return distribution (distribution_name ).requires
0 commit comments