Skip to content

Commit 6713a55

Browse files
wip state - type checking and naive packing start - still broken mess
1 parent c6da0c4 commit 6713a55

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

src/execnet/_dictimport.py

+48-25
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import base64
66
import json
77
import os
8+
import pkgutil
89
import sys
910
import types
1011
import zlib
@@ -13,13 +14,16 @@
1314
from importlib.metadata import Distribution
1415
from importlib.metadata import DistributionFinder
1516
from typing import IO
16-
from typing import TYPE_CHECKING
1717
from typing import Any
1818
from typing import Iterable
19+
from typing import NamedTuple
20+
from typing import NewType
21+
from typing import Protocol
1922
from typing import Sequence
23+
from typing import cast
24+
from typing import runtime_checkable
2025

21-
if TYPE_CHECKING:
22-
pass
26+
ModuleName = NewType("ModuleName", str)
2327

2428

2529
class DictDistribution(Distribution):
@@ -35,56 +39,58 @@ def locate_file(self, path: str | os.PathLike[str]) -> os.PathLike[str]:
3539
raise FileNotFoundError(path)
3640

3741

42+
class ModuleInfo(NamedTuple):
43+
name: ModuleName
44+
is_pkg: bool
45+
source: str
46+
47+
3848
class DictImporter(DistributionFinder, Loader):
3949
"""a limited loader/importer for distributins send via json-lines"""
4050

41-
def __init__(self, sources: dict[str, str], distribution: DictDistribution):
51+
def __init__(
52+
self, sources: dict[ModuleName, ModuleInfo], distribution: DictDistribution
53+
):
4254
self.sources = sources
4355
self.distribution = distribution
4456

4557
def find_distributions(
46-
self, context: DistributionFinder.Context = DistributionFinder.Context()
58+
self, context: DistributionFinder.Context | None = None
4759
) -> Iterable[Distribution]:
60+
# TODO: filter
4861
return [self.distribution]
4962

5063
def find_module(
5164
self, fullname: str, path: Sequence[str | bytes] | None = None
5265
) -> Loader | None:
53-
if fullname in self.sources:
54-
return self
55-
if fullname + ".__init__" in self.sources:
66+
if ModuleName(fullname) in self.sources:
5667
return self
5768
return None
5869

59-
def load_module(self, fullname):
70+
def load_module(self, fullname: str) -> types.ModuleType:
6071
# print "load_module:", fullname
61-
from types import ModuleType
6272

63-
try:
64-
s = self.sources[fullname]
65-
is_pkg = False
66-
except KeyError:
67-
s = self.sources[fullname + ".__init__"]
68-
is_pkg = True
73+
info = self.sources[ModuleName(fullname)]
6974

70-
co = compile(s, fullname, "exec")
71-
module = sys.modules.setdefault(fullname, ModuleType(fullname))
75+
co = compile(info.source, fullname, "exec")
76+
module = sys.modules.setdefault(fullname, types.ModuleType(fullname))
7277
module.__loader__ = self
73-
if is_pkg:
78+
if info.is_pkg:
7479
module.__path__ = [fullname]
7580

7681
exec(co, module.__dict__)
7782
return sys.modules[fullname]
7883

7984
def get_source(self, name: str) -> str | None:
80-
res = self.sources.get(name)
85+
res = self.sources.get(ModuleName(name))
8186
if res is None:
82-
res = self.sources.get(name + ".__init__")
83-
return res
87+
return None
88+
else:
89+
return res.source
8490

8591

8692
def bootstrap(
87-
modules: dict[str, str],
93+
modules: dict[ModuleName, ModuleInfo],
8894
distribution: dict[str, str],
8995
entry: str,
9096
args: dict[str, Any],
@@ -100,7 +106,7 @@ def bootstrap(
100106
entry_func(**args)
101107

102108

103-
def bootstrap_stdin(stream: IO) -> None:
109+
def bootstrap_stdin(stream: IO[bytes] | IO[str]) -> None:
104110
bootstrap_args = decode_b85_zip_json(stream.readline())
105111
bootstrap(**bootstrap_args)
106112

@@ -111,9 +117,26 @@ def decode_b85_zip_json(encoded: bytes | str):
111117
return json.loads(unpacked)
112118

113119

114-
def naive_pack_module(module: types.ModuleType, dist: Distribution):
120+
@runtime_checkable
121+
class SourceProvidingLoader(Protocol):
122+
def get_source(self, name: str) -> str:
123+
...
124+
125+
126+
def naive_pack_module(module: types.ModuleType, dist: Distribution) -> object:
115127
assert module.__file__ is not None
116128
assert module.__path__
129+
data: dict[ModuleName, ModuleInfo] = {}
130+
for info in pkgutil.walk_packages(module.__path__, f"{module.__name__}."):
131+
spec = info.module_finder.find_spec(info.name, None)
132+
assert spec is not None
133+
loader = cast(SourceProvidingLoader, spec.loader)
134+
135+
source = loader.get_source(info.name)
136+
data[ModuleName(info.name)] = ModuleInfo(
137+
name=ModuleName(info.name), is_pkg=info.ispkg, source=source
138+
)
139+
return data
117140

118141

119142
if __name__ == "__main__":

0 commit comments

Comments
 (0)