11import importlib .metadata
2+ import pathlib
23import re
34from functools import lru_cache , reduce
45from typing import Dict , List
56
7+ from polylith .distributions import caching
8+
69SUB_DEP_SEPARATORS = r"[\s!=;><\^~]"
710
811
@@ -25,9 +28,11 @@ def map_sub_packages(acc, dist) -> dict:
2528 return {** acc , ** dist_subpackages (dist )}
2629
2730
28- def parsed_namespaces_from_files (dist ) -> List [str ]:
29- name = dist .metadata ["name" ]
30- files = dist .files or []
31+ def parsed_namespaces_from_files (dist , name : str ) -> List [str ]:
32+ if not caching .exists (name ):
33+ files = dist .files or []
34+ python_files = [f for f in files if f .suffix == ".py" ]
35+ caching .add (name , python_files )
3136
3237 normalized_name = str .replace (name , "-" , "_" )
3338 to_ignore = {
@@ -38,7 +43,7 @@ def parsed_namespaces_from_files(dist) -> List[str]:
3843 ".." ,
3944 }
4045
41- filtered = [ f for f in files if f . suffix == ".py" ]
46+ filtered : List [ pathlib . PurePosixPath ] = caching . get ( name )
4247 top_folders = {f .parts [0 ] for f in filtered if len (f .parts ) > 1 }
4348 namespaces = {t for t in top_folders if t not in to_ignore }
4449
@@ -49,17 +54,19 @@ def parsed_top_level_namespace(namespaces: List[str]) -> List[str]:
4954 return [str .replace (ns , "/" , "." ) for ns in namespaces ]
5055
5156
52- def top_level_packages (dist ) -> List [str ]:
57+ def top_level_packages (dist , name : str ) -> List [str ]:
5358 top_level = dist .read_text ("top_level.txt" )
5459
5560 namespaces = str .split (top_level or "" )
5661
57- return parsed_top_level_namespace (namespaces ) or parsed_namespaces_from_files (dist )
62+ return parsed_top_level_namespace (namespaces ) or parsed_namespaces_from_files (
63+ dist , name
64+ )
5865
5966
6067def mapped_packages (dist ) -> dict :
61- packages = top_level_packages (dist )
6268 name = dist .metadata ["name" ]
69+ packages = top_level_packages (dist , name )
6370
6471 return {name : packages } if packages else {}
6572
@@ -83,6 +90,14 @@ def get_distributions() -> list:
8390 return list (importlib .metadata .distributions ())
8491
8592
93+ @lru_cache
94+ def package_distributions_from_importlib () -> dict :
95+ # added in Python 3.10
96+ fn = getattr (importlib .metadata , "packages_distributions" , None )
97+
98+ return fn () if fn else {}
99+
100+
86101def get_packages_distributions (project_dependencies : set ) -> set :
87102 """Return the mapped top namespace from an import
88103
@@ -93,10 +108,7 @@ def get_packages_distributions(project_dependencies: set) -> set:
93108 Note: available for Python >= 3.10
94109 """
95110
96- # added in Python 3.10
97- fn = getattr (importlib .metadata , "packages_distributions" , None )
98-
99- dists = fn () if fn else {}
111+ dists = package_distributions_from_importlib ()
100112
101113 common = {k for k , v in dists .items () if project_dependencies .intersection (set (v ))}
102114
0 commit comments