ob-metaflow 2.11.13.1__py2.py3-none-any.whl → 2.19.7.1rc0__py2.py3-none-any.whl

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 (289) hide show
  1. metaflow/R.py +10 -7
  2. metaflow/__init__.py +40 -25
  3. metaflow/_vendor/imghdr/__init__.py +186 -0
  4. metaflow/_vendor/importlib_metadata/__init__.py +1063 -0
  5. metaflow/_vendor/importlib_metadata/_adapters.py +68 -0
  6. metaflow/_vendor/importlib_metadata/_collections.py +30 -0
  7. metaflow/_vendor/importlib_metadata/_compat.py +71 -0
  8. metaflow/_vendor/importlib_metadata/_functools.py +104 -0
  9. metaflow/_vendor/importlib_metadata/_itertools.py +73 -0
  10. metaflow/_vendor/importlib_metadata/_meta.py +48 -0
  11. metaflow/_vendor/importlib_metadata/_text.py +99 -0
  12. metaflow/_vendor/importlib_metadata/py.typed +0 -0
  13. metaflow/_vendor/typeguard/__init__.py +48 -0
  14. metaflow/_vendor/typeguard/_checkers.py +1070 -0
  15. metaflow/_vendor/typeguard/_config.py +108 -0
  16. metaflow/_vendor/typeguard/_decorators.py +233 -0
  17. metaflow/_vendor/typeguard/_exceptions.py +42 -0
  18. metaflow/_vendor/typeguard/_functions.py +308 -0
  19. metaflow/_vendor/typeguard/_importhook.py +213 -0
  20. metaflow/_vendor/typeguard/_memo.py +48 -0
  21. metaflow/_vendor/typeguard/_pytest_plugin.py +127 -0
  22. metaflow/_vendor/typeguard/_suppression.py +86 -0
  23. metaflow/_vendor/typeguard/_transformer.py +1229 -0
  24. metaflow/_vendor/typeguard/_union_transformer.py +55 -0
  25. metaflow/_vendor/typeguard/_utils.py +173 -0
  26. metaflow/_vendor/typeguard/py.typed +0 -0
  27. metaflow/_vendor/typing_extensions.py +3641 -0
  28. metaflow/_vendor/v3_7/importlib_metadata/__init__.py +1063 -0
  29. metaflow/_vendor/v3_7/importlib_metadata/_adapters.py +68 -0
  30. metaflow/_vendor/v3_7/importlib_metadata/_collections.py +30 -0
  31. metaflow/_vendor/v3_7/importlib_metadata/_compat.py +71 -0
  32. metaflow/_vendor/v3_7/importlib_metadata/_functools.py +104 -0
  33. metaflow/_vendor/v3_7/importlib_metadata/_itertools.py +73 -0
  34. metaflow/_vendor/v3_7/importlib_metadata/_meta.py +48 -0
  35. metaflow/_vendor/v3_7/importlib_metadata/_text.py +99 -0
  36. metaflow/_vendor/v3_7/importlib_metadata/py.typed +0 -0
  37. metaflow/_vendor/v3_7/typeguard/__init__.py +48 -0
  38. metaflow/_vendor/v3_7/typeguard/_checkers.py +906 -0
  39. metaflow/_vendor/v3_7/typeguard/_config.py +108 -0
  40. metaflow/_vendor/v3_7/typeguard/_decorators.py +237 -0
  41. metaflow/_vendor/v3_7/typeguard/_exceptions.py +42 -0
  42. metaflow/_vendor/v3_7/typeguard/_functions.py +310 -0
  43. metaflow/_vendor/v3_7/typeguard/_importhook.py +213 -0
  44. metaflow/_vendor/v3_7/typeguard/_memo.py +48 -0
  45. metaflow/_vendor/v3_7/typeguard/_pytest_plugin.py +100 -0
  46. metaflow/_vendor/v3_7/typeguard/_suppression.py +88 -0
  47. metaflow/_vendor/v3_7/typeguard/_transformer.py +1207 -0
  48. metaflow/_vendor/v3_7/typeguard/_union_transformer.py +54 -0
  49. metaflow/_vendor/v3_7/typeguard/_utils.py +169 -0
  50. metaflow/_vendor/v3_7/typeguard/py.typed +0 -0
  51. metaflow/_vendor/v3_7/typing_extensions.py +3072 -0
  52. metaflow/_vendor/yaml/__init__.py +427 -0
  53. metaflow/_vendor/yaml/composer.py +139 -0
  54. metaflow/_vendor/yaml/constructor.py +748 -0
  55. metaflow/_vendor/yaml/cyaml.py +101 -0
  56. metaflow/_vendor/yaml/dumper.py +62 -0
  57. metaflow/_vendor/yaml/emitter.py +1137 -0
  58. metaflow/_vendor/yaml/error.py +75 -0
  59. metaflow/_vendor/yaml/events.py +86 -0
  60. metaflow/_vendor/yaml/loader.py +63 -0
  61. metaflow/_vendor/yaml/nodes.py +49 -0
  62. metaflow/_vendor/yaml/parser.py +589 -0
  63. metaflow/_vendor/yaml/reader.py +185 -0
  64. metaflow/_vendor/yaml/representer.py +389 -0
  65. metaflow/_vendor/yaml/resolver.py +227 -0
  66. metaflow/_vendor/yaml/scanner.py +1435 -0
  67. metaflow/_vendor/yaml/serializer.py +111 -0
  68. metaflow/_vendor/yaml/tokens.py +104 -0
  69. metaflow/cards.py +5 -0
  70. metaflow/cli.py +331 -785
  71. metaflow/cli_args.py +17 -0
  72. metaflow/cli_components/__init__.py +0 -0
  73. metaflow/cli_components/dump_cmd.py +96 -0
  74. metaflow/cli_components/init_cmd.py +52 -0
  75. metaflow/cli_components/run_cmds.py +546 -0
  76. metaflow/cli_components/step_cmd.py +334 -0
  77. metaflow/cli_components/utils.py +140 -0
  78. metaflow/client/__init__.py +1 -0
  79. metaflow/client/core.py +467 -73
  80. metaflow/client/filecache.py +75 -35
  81. metaflow/clone_util.py +7 -1
  82. metaflow/cmd/code/__init__.py +231 -0
  83. metaflow/cmd/develop/stub_generator.py +756 -288
  84. metaflow/cmd/develop/stubs.py +12 -28
  85. metaflow/cmd/main_cli.py +6 -4
  86. metaflow/cmd/make_wrapper.py +78 -0
  87. metaflow/datastore/__init__.py +1 -0
  88. metaflow/datastore/content_addressed_store.py +41 -10
  89. metaflow/datastore/datastore_set.py +11 -2
  90. metaflow/datastore/flow_datastore.py +156 -10
  91. metaflow/datastore/spin_datastore.py +91 -0
  92. metaflow/datastore/task_datastore.py +154 -39
  93. metaflow/debug.py +5 -0
  94. metaflow/decorators.py +404 -78
  95. metaflow/exception.py +8 -2
  96. metaflow/extension_support/__init__.py +527 -376
  97. metaflow/extension_support/_empty_file.py +2 -2
  98. metaflow/extension_support/plugins.py +49 -31
  99. metaflow/flowspec.py +482 -33
  100. metaflow/graph.py +210 -42
  101. metaflow/includefile.py +84 -40
  102. metaflow/lint.py +141 -22
  103. metaflow/meta_files.py +13 -0
  104. metaflow/{metadata → metadata_provider}/heartbeat.py +24 -8
  105. metaflow/{metadata → metadata_provider}/metadata.py +86 -1
  106. metaflow/metaflow_config.py +175 -28
  107. metaflow/metaflow_config_funcs.py +51 -3
  108. metaflow/metaflow_current.py +4 -10
  109. metaflow/metaflow_environment.py +139 -53
  110. metaflow/metaflow_git.py +115 -0
  111. metaflow/metaflow_profile.py +18 -0
  112. metaflow/metaflow_version.py +150 -66
  113. metaflow/mflog/__init__.py +4 -3
  114. metaflow/mflog/save_logs.py +2 -2
  115. metaflow/multicore_utils.py +31 -14
  116. metaflow/package/__init__.py +673 -0
  117. metaflow/packaging_sys/__init__.py +880 -0
  118. metaflow/packaging_sys/backend.py +128 -0
  119. metaflow/packaging_sys/distribution_support.py +153 -0
  120. metaflow/packaging_sys/tar_backend.py +99 -0
  121. metaflow/packaging_sys/utils.py +54 -0
  122. metaflow/packaging_sys/v1.py +527 -0
  123. metaflow/parameters.py +149 -28
  124. metaflow/plugins/__init__.py +74 -5
  125. metaflow/plugins/airflow/airflow.py +40 -25
  126. metaflow/plugins/airflow/airflow_cli.py +22 -5
  127. metaflow/plugins/airflow/airflow_decorator.py +1 -1
  128. metaflow/plugins/airflow/airflow_utils.py +5 -3
  129. metaflow/plugins/airflow/sensors/base_sensor.py +4 -4
  130. metaflow/plugins/airflow/sensors/external_task_sensor.py +2 -2
  131. metaflow/plugins/airflow/sensors/s3_sensor.py +2 -2
  132. metaflow/plugins/argo/argo_client.py +78 -33
  133. metaflow/plugins/argo/argo_events.py +6 -6
  134. metaflow/plugins/argo/argo_workflows.py +2410 -527
  135. metaflow/plugins/argo/argo_workflows_cli.py +571 -121
  136. metaflow/plugins/argo/argo_workflows_decorator.py +43 -12
  137. metaflow/plugins/argo/argo_workflows_deployer.py +106 -0
  138. metaflow/plugins/argo/argo_workflows_deployer_objects.py +453 -0
  139. metaflow/plugins/argo/capture_error.py +73 -0
  140. metaflow/plugins/argo/conditional_input_paths.py +35 -0
  141. metaflow/plugins/argo/exit_hooks.py +209 -0
  142. metaflow/plugins/argo/jobset_input_paths.py +15 -0
  143. metaflow/plugins/argo/param_val.py +19 -0
  144. metaflow/plugins/aws/aws_client.py +10 -3
  145. metaflow/plugins/aws/aws_utils.py +55 -2
  146. metaflow/plugins/aws/batch/batch.py +72 -5
  147. metaflow/plugins/aws/batch/batch_cli.py +33 -10
  148. metaflow/plugins/aws/batch/batch_client.py +4 -3
  149. metaflow/plugins/aws/batch/batch_decorator.py +102 -35
  150. metaflow/plugins/aws/secrets_manager/aws_secrets_manager_secrets_provider.py +13 -10
  151. metaflow/plugins/aws/step_functions/dynamo_db_client.py +0 -3
  152. metaflow/plugins/aws/step_functions/production_token.py +1 -1
  153. metaflow/plugins/aws/step_functions/step_functions.py +65 -8
  154. metaflow/plugins/aws/step_functions/step_functions_cli.py +101 -7
  155. metaflow/plugins/aws/step_functions/step_functions_decorator.py +1 -2
  156. metaflow/plugins/aws/step_functions/step_functions_deployer.py +97 -0
  157. metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +264 -0
  158. metaflow/plugins/azure/azure_exceptions.py +1 -1
  159. metaflow/plugins/azure/azure_secret_manager_secrets_provider.py +240 -0
  160. metaflow/plugins/azure/azure_tail.py +1 -1
  161. metaflow/plugins/azure/includefile_support.py +2 -0
  162. metaflow/plugins/cards/card_cli.py +66 -30
  163. metaflow/plugins/cards/card_creator.py +25 -1
  164. metaflow/plugins/cards/card_datastore.py +21 -49
  165. metaflow/plugins/cards/card_decorator.py +132 -8
  166. metaflow/plugins/cards/card_modules/basic.py +112 -17
  167. metaflow/plugins/cards/card_modules/bundle.css +1 -1
  168. metaflow/plugins/cards/card_modules/card.py +16 -1
  169. metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
  170. metaflow/plugins/cards/card_modules/components.py +665 -28
  171. metaflow/plugins/cards/card_modules/convert_to_native_type.py +36 -7
  172. metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
  173. metaflow/plugins/cards/card_modules/main.css +1 -0
  174. metaflow/plugins/cards/card_modules/main.js +68 -49
  175. metaflow/plugins/cards/card_modules/renderer_tools.py +1 -0
  176. metaflow/plugins/cards/card_modules/test_cards.py +26 -12
  177. metaflow/plugins/cards/card_server.py +39 -14
  178. metaflow/plugins/cards/component_serializer.py +2 -9
  179. metaflow/plugins/cards/metadata.py +22 -0
  180. metaflow/plugins/catch_decorator.py +9 -0
  181. metaflow/plugins/datastores/azure_storage.py +10 -1
  182. metaflow/plugins/datastores/gs_storage.py +6 -2
  183. metaflow/plugins/datastores/local_storage.py +12 -6
  184. metaflow/plugins/datastores/spin_storage.py +12 -0
  185. metaflow/plugins/datatools/local.py +2 -0
  186. metaflow/plugins/datatools/s3/s3.py +126 -75
  187. metaflow/plugins/datatools/s3/s3op.py +254 -121
  188. metaflow/plugins/env_escape/__init__.py +3 -3
  189. metaflow/plugins/env_escape/client_modules.py +102 -72
  190. metaflow/plugins/env_escape/server.py +7 -0
  191. metaflow/plugins/env_escape/stub.py +24 -5
  192. metaflow/plugins/events_decorator.py +343 -185
  193. metaflow/plugins/exit_hook/__init__.py +0 -0
  194. metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
  195. metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
  196. metaflow/plugins/gcp/__init__.py +1 -1
  197. metaflow/plugins/gcp/gcp_secret_manager_secrets_provider.py +11 -6
  198. metaflow/plugins/gcp/gs_tail.py +10 -6
  199. metaflow/plugins/gcp/includefile_support.py +3 -0
  200. metaflow/plugins/kubernetes/kube_utils.py +108 -0
  201. metaflow/plugins/kubernetes/kubernetes.py +411 -130
  202. metaflow/plugins/kubernetes/kubernetes_cli.py +168 -36
  203. metaflow/plugins/kubernetes/kubernetes_client.py +104 -2
  204. metaflow/plugins/kubernetes/kubernetes_decorator.py +246 -88
  205. metaflow/plugins/kubernetes/kubernetes_job.py +253 -581
  206. metaflow/plugins/kubernetes/kubernetes_jobsets.py +1071 -0
  207. metaflow/plugins/kubernetes/spot_metadata_cli.py +69 -0
  208. metaflow/plugins/kubernetes/spot_monitor_sidecar.py +109 -0
  209. metaflow/plugins/logs_cli.py +359 -0
  210. metaflow/plugins/{metadata → metadata_providers}/local.py +144 -84
  211. metaflow/plugins/{metadata → metadata_providers}/service.py +103 -26
  212. metaflow/plugins/metadata_providers/spin.py +16 -0
  213. metaflow/plugins/package_cli.py +36 -24
  214. metaflow/plugins/parallel_decorator.py +128 -11
  215. metaflow/plugins/parsers.py +16 -0
  216. metaflow/plugins/project_decorator.py +51 -5
  217. metaflow/plugins/pypi/bootstrap.py +357 -105
  218. metaflow/plugins/pypi/conda_decorator.py +82 -81
  219. metaflow/plugins/pypi/conda_environment.py +187 -52
  220. metaflow/plugins/pypi/micromamba.py +157 -47
  221. metaflow/plugins/pypi/parsers.py +268 -0
  222. metaflow/plugins/pypi/pip.py +88 -13
  223. metaflow/plugins/pypi/pypi_decorator.py +37 -1
  224. metaflow/plugins/pypi/utils.py +48 -2
  225. metaflow/plugins/resources_decorator.py +2 -2
  226. metaflow/plugins/secrets/__init__.py +3 -0
  227. metaflow/plugins/secrets/secrets_decorator.py +26 -181
  228. metaflow/plugins/secrets/secrets_func.py +49 -0
  229. metaflow/plugins/secrets/secrets_spec.py +101 -0
  230. metaflow/plugins/secrets/utils.py +74 -0
  231. metaflow/plugins/tag_cli.py +4 -7
  232. metaflow/plugins/test_unbounded_foreach_decorator.py +41 -6
  233. metaflow/plugins/timeout_decorator.py +3 -3
  234. metaflow/plugins/uv/__init__.py +0 -0
  235. metaflow/plugins/uv/bootstrap.py +128 -0
  236. metaflow/plugins/uv/uv_environment.py +72 -0
  237. metaflow/procpoll.py +1 -1
  238. metaflow/pylint_wrapper.py +5 -1
  239. metaflow/runner/__init__.py +0 -0
  240. metaflow/runner/click_api.py +717 -0
  241. metaflow/runner/deployer.py +470 -0
  242. metaflow/runner/deployer_impl.py +201 -0
  243. metaflow/runner/metaflow_runner.py +714 -0
  244. metaflow/runner/nbdeploy.py +132 -0
  245. metaflow/runner/nbrun.py +225 -0
  246. metaflow/runner/subprocess_manager.py +650 -0
  247. metaflow/runner/utils.py +335 -0
  248. metaflow/runtime.py +1078 -260
  249. metaflow/sidecar/sidecar_worker.py +1 -1
  250. metaflow/system/__init__.py +5 -0
  251. metaflow/system/system_logger.py +85 -0
  252. metaflow/system/system_monitor.py +108 -0
  253. metaflow/system/system_utils.py +19 -0
  254. metaflow/task.py +521 -225
  255. metaflow/tracing/__init__.py +7 -7
  256. metaflow/tracing/span_exporter.py +31 -38
  257. metaflow/tracing/tracing_modules.py +38 -43
  258. metaflow/tuple_util.py +27 -0
  259. metaflow/user_configs/__init__.py +0 -0
  260. metaflow/user_configs/config_options.py +563 -0
  261. metaflow/user_configs/config_parameters.py +598 -0
  262. metaflow/user_decorators/__init__.py +0 -0
  263. metaflow/user_decorators/common.py +144 -0
  264. metaflow/user_decorators/mutable_flow.py +512 -0
  265. metaflow/user_decorators/mutable_step.py +424 -0
  266. metaflow/user_decorators/user_flow_decorator.py +264 -0
  267. metaflow/user_decorators/user_step_decorator.py +749 -0
  268. metaflow/util.py +243 -27
  269. metaflow/vendor.py +23 -7
  270. metaflow/version.py +1 -1
  271. ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Makefile +355 -0
  272. ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Tiltfile +726 -0
  273. ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/pick_services.sh +105 -0
  274. ob_metaflow-2.19.7.1rc0.dist-info/METADATA +87 -0
  275. ob_metaflow-2.19.7.1rc0.dist-info/RECORD +445 -0
  276. {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
  277. {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +1 -0
  278. metaflow/_vendor/v3_5/__init__.py +0 -1
  279. metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
  280. metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
  281. metaflow/package.py +0 -188
  282. ob_metaflow-2.11.13.1.dist-info/METADATA +0 -85
  283. ob_metaflow-2.11.13.1.dist-info/RECORD +0 -308
  284. /metaflow/_vendor/{v3_5/zipp.py → zipp.py} +0 -0
  285. /metaflow/{metadata → metadata_provider}/__init__.py +0 -0
  286. /metaflow/{metadata → metadata_provider}/util.py +0 -0
  287. /metaflow/plugins/{metadata → metadata_providers}/__init__.py +0 -0
  288. {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info/licenses}/LICENSE +0 -0
  289. {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  import atexit
2
2
  import importlib
3
+ import importlib.util
3
4
  import itertools
4
5
  import pickle
5
6
  import re
@@ -41,6 +42,8 @@ class _WrappedModule(object):
41
42
  def __getattr__(self, name):
42
43
  if name == "__loader__":
43
44
  return self._loader
45
+ if name == "__spec__":
46
+ return importlib.util.spec_from_loader(self._prefix, self._loader)
44
47
  if name in ("__name__", "__package__"):
45
48
  return self._prefix
46
49
  if name in ("__file__", "__path__"):
@@ -71,7 +74,8 @@ class _WrappedModule(object):
71
74
  # Try to see if this is a submodule that we can load
72
75
  m = None
73
76
  try:
74
- m = self._loader.load_module(".".join([self._prefix, name]))
77
+ submodule_name = ".".join([self._prefix, name])
78
+ m = importlib.import_module(submodule_name)
75
79
  except ImportError:
76
80
  pass
77
81
  if m is None:
@@ -117,7 +121,28 @@ class _WrappedModule(object):
117
121
 
118
122
 
119
123
  class ModuleImporter(object):
120
- # This ModuleImporter implements the Importer Protocol defined in PEP 302
124
+ """
125
+ A custom import hook that proxies module imports to a different Python environment.
126
+
127
+ This class implements the MetaPathFinder and Loader protocols (PEP 451) to enable
128
+ "environment escape" - allowing the current Python process to import and use modules
129
+ from a different Python interpreter with potentially different versions or packages.
130
+
131
+ When a module is imported through this importer:
132
+ 1. A client spawns a server process in the target Python environment
133
+ 2. The module is loaded in the remote environment
134
+ 3. A _WrappedModule proxy is returned that forwards all operations (function calls,
135
+ attribute access, etc.) to the remote environment via RPC
136
+ 4. Data is serialized/deserialized using pickle for cross-environment communication
137
+
138
+ Args:
139
+ python_executable: Path to the Python interpreter for the remote environment
140
+ pythonpath: Python path to use in the remote environment
141
+ max_pickle_version: Maximum pickle protocol version supported by remote interpreter
142
+ config_dir: Directory containing configuration for the environment escape
143
+ module_prefixes: List of module name prefixes to handle
144
+ """
145
+
121
146
  def __init__(
122
147
  self,
123
148
  python_executable,
@@ -135,84 +160,89 @@ class ModuleImporter(object):
135
160
  self._handled_modules = None
136
161
  self._aliases = {}
137
162
 
138
- def find_module(self, fullname, path=None):
163
+ def find_spec(self, fullname, path=None, target=None):
139
164
  if self._handled_modules is not None:
140
165
  if get_canonical_name(fullname, self._aliases) in self._handled_modules:
141
- return self
166
+ return importlib.util.spec_from_loader(fullname, self)
142
167
  return None
143
168
  if any([fullname.startswith(prefix) for prefix in self._module_prefixes]):
144
169
  # We potentially handle this
145
- return self
170
+ return importlib.util.spec_from_loader(fullname, self)
146
171
  return None
147
172
 
148
- def load_module(self, fullname):
149
- if fullname in sys.modules:
150
- return sys.modules[fullname]
151
- if self._client is None:
152
- if sys.version_info[0] < 3:
153
- raise NotImplementedError(
154
- "Environment escape imports are not supported in Python 2"
155
- )
156
- # We initialize a client and query the modules we handle
157
- # The max_pickle_version is the pickle version that the server (so
158
- # the underlying interpreter we call into) supports; we determine
159
- # what version the current environment support and take the minimum
160
- # of those two
161
- max_pickle_version = min(self._max_pickle_version, pickle.HIGHEST_PROTOCOL)
162
-
163
- self._client = Client(
164
- self._module_prefixes,
165
- self._python_executable,
166
- self._pythonpath,
167
- max_pickle_version,
168
- self._config_dir,
169
- )
170
- atexit.register(_clean_client, self._client)
171
-
172
- # Get information about overrides and what the server knows about
173
- exports = self._client.get_exports()
174
-
175
- prefixes = set()
176
- export_classes = exports.get("classes", [])
177
- export_functions = exports.get("functions", [])
178
- export_values = exports.get("values", [])
179
- export_exceptions = exports.get("exceptions", [])
180
- self._aliases = exports.get("aliases", {})
181
- for name in itertools.chain(
182
- export_classes,
183
- export_functions,
184
- export_values,
185
- (e[0] for e in export_exceptions),
186
- ):
187
- splits = name.rsplit(".", 1)
188
- prefixes.add(splits[0])
189
- # We will make sure that we create modules even for "empty" prefixes
190
- # because packages are always loaded hierarchically so if we have
191
- # something in `a.b.c` but nothing directly in `a`, we still need to
192
- # create a module named `a`. There is probably a better way of doing this
193
- all_prefixes = list(prefixes)
194
- for prefix in all_prefixes:
195
- parts = prefix.split(".")
196
- cur = parts[0]
197
- for i in range(1, len(parts)):
198
- prefixes.add(cur)
199
- cur = ".".join([cur, parts[i]])
200
-
201
- # We now know all the modules that we can handle. We update
202
- # handled_module and return the module if we have it or raise ImportError
203
- self._handled_modules = {}
204
- for prefix in prefixes:
205
- self._handled_modules[prefix] = _WrappedModule(
206
- self, prefix, exports, self._client
207
- )
173
+ def create_module(self, spec):
174
+ # Return the pre-created wrapped module for this spec
175
+ self._initialize_client()
176
+
177
+ fullname = spec.name
208
178
  canonical_fullname = get_canonical_name(fullname, self._aliases)
209
- # Modules are created canonically but we need to return something for any
210
- # of the aliases.
211
- module = self._handled_modules.get(canonical_fullname)
212
- if module is None:
213
- raise ImportError
214
- sys.modules[fullname] = module
215
- return module
179
+ # Modules are created canonically but we need to handle any of the aliases.
180
+ wrapped_module = self._handled_modules.get(canonical_fullname)
181
+ if wrapped_module is None:
182
+ raise ImportError(f"No module named '{fullname}'")
183
+ return wrapped_module
184
+
185
+ def exec_module(self, module):
186
+ # No initialization needed since the wrapped module returned by
187
+ # create_module() is fully initialized
188
+ pass
189
+
190
+ def _initialize_client(self):
191
+ if self._client is not None:
192
+ return
193
+
194
+ # We initialize a client and query the modules we handle
195
+ # The max_pickle_version is the pickle version that the server (so
196
+ # the underlying interpreter we call into) supports; we determine
197
+ # what version the current environment support and take the minimum
198
+ # of those two
199
+ max_pickle_version = min(self._max_pickle_version, pickle.HIGHEST_PROTOCOL)
200
+
201
+ self._client = Client(
202
+ self._module_prefixes,
203
+ self._python_executable,
204
+ self._pythonpath,
205
+ max_pickle_version,
206
+ self._config_dir,
207
+ )
208
+ atexit.register(_clean_client, self._client)
209
+
210
+ # Get information about overrides and what the server knows about
211
+ exports = self._client.get_exports()
212
+
213
+ prefixes = set()
214
+ export_classes = exports.get("classes", [])
215
+ export_functions = exports.get("functions", [])
216
+ export_values = exports.get("values", [])
217
+ export_exceptions = exports.get("exceptions", [])
218
+ self._aliases = exports.get("aliases", {})
219
+ for name in itertools.chain(
220
+ export_classes,
221
+ export_functions,
222
+ export_values,
223
+ (e[0] for e in export_exceptions),
224
+ ):
225
+ splits = name.rsplit(".", 1)
226
+ prefixes.add(splits[0])
227
+ # We will make sure that we create modules even for "empty" prefixes
228
+ # because packages are always loaded hierarchically so if we have
229
+ # something in `a.b.c` but nothing directly in `a`, we still need to
230
+ # create a module named `a`. There is probably a better way of doing this
231
+ all_prefixes = list(prefixes)
232
+ for prefix in all_prefixes:
233
+ parts = prefix.split(".")
234
+ cur = parts[0]
235
+ for i in range(1, len(parts)):
236
+ prefixes.add(cur)
237
+ cur = ".".join([cur, parts[i]])
238
+
239
+ # We now know all the modules that we can handle. We update
240
+ # handled_module and return the module if we have it or raise ImportError
241
+ self._handled_modules = {}
242
+ for prefix in prefixes:
243
+ self._handled_modules[prefix] = _WrappedModule(
244
+ self, prefix, exports, self._client
245
+ )
216
246
 
217
247
 
218
248
  def create_modules(python_executable, pythonpath, max_pickle_version, path, prefixes):
@@ -264,6 +264,7 @@ class Server(object):
264
264
  def serve(self, path=None, port=None):
265
265
  # Open up a connection
266
266
  if path is not None:
267
+ # Keep the print line to facilitate debugging
267
268
  # print("SERVER: Starting at %s" % path)
268
269
  sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
269
270
  __try_op__("bind", sock.bind, BIND_RETRY, path)
@@ -503,6 +504,12 @@ class Server(object):
503
504
  class_type = self._known_classes.get(class_name)
504
505
  if class_type is None:
505
506
  raise ValueError("Unknown class %s" % class_name)
507
+ # Check if __init__ is overridden
508
+ override_mapping = self._overrides.get(class_type)
509
+ if override_mapping:
510
+ override_func = override_mapping.get("__init__")
511
+ if override_func:
512
+ return override_func(None, class_type, *args, **kwargs)
506
513
  return class_type(*args, **kwargs)
507
514
 
508
515
  def _handle_subclasscheck(self, target, class_name, otherclass_name, reverse=False):
@@ -146,7 +146,7 @@ class Stub(with_metaclass(StubMetaClass, object)):
146
146
  return object.__getattribute__(self, name)
147
147
 
148
148
  def __getattr__(self, name):
149
- if name in DELETED_ATTRS:
149
+ if name in DELETED_ATTRS or self.___is_returned_exception___:
150
150
  raise AttributeError()
151
151
  return fwd_request(self, OP_GETATTR, name)
152
152
 
@@ -166,6 +166,8 @@ class Stub(with_metaclass(StubMetaClass, object)):
166
166
  ):
167
167
  object.__setattr__(self, name, value)
168
168
  else:
169
+ if self.___is_returned_exception___:
170
+ raise AttributeError()
169
171
  fwd_request(self, OP_SETATTR, name, value)
170
172
 
171
173
  def __dir__(self):
@@ -274,9 +276,22 @@ class MetaWithConnection(StubMetaClass):
274
276
  if len(args) > 0 and id(args[0]) == id(cls.___class_connection___):
275
277
  return super(MetaWithConnection, cls).__call__(*args, **kwargs)
276
278
  else:
277
- return cls.___class_connection___.stub_request(
278
- None, OP_INIT, cls.___class_remote_class_name___, *args, **kwargs
279
- )
279
+ if hasattr(cls, "__overriden_init__"):
280
+ return cls.__overriden_init__(
281
+ None,
282
+ functools.partial(
283
+ cls.___class_connection___.stub_request,
284
+ None,
285
+ OP_INIT,
286
+ cls.___class_remote_class_name___,
287
+ ),
288
+ *args,
289
+ **kwargs
290
+ )
291
+ else:
292
+ return cls.___class_connection___.stub_request(
293
+ None, OP_INIT, cls.___class_remote_class_name___, *args, **kwargs
294
+ )
280
295
 
281
296
  def __subclasscheck__(cls, subclass):
282
297
  subclass_name = "%s.%s" % (subclass.__module__, subclass.__name__)
@@ -379,7 +394,10 @@ def create_class(
379
394
  name = name[7:]
380
395
  method_type = CLASS_METHOD
381
396
  if name in overriden_methods:
382
- if method_type == NORMAL_METHOD:
397
+ if name == "__init__":
398
+ class_dict["__overriden_init__"] = overriden_methods["__init__"]
399
+
400
+ elif method_type == NORMAL_METHOD:
383
401
  class_dict[name] = (
384
402
  lambda override, orig_method: lambda obj, *args, **kwargs: override(
385
403
  obj, functools.partial(orig_method, obj), *args, **kwargs
@@ -410,6 +428,7 @@ def create_class(
410
428
  class_dict[name] = _make_method(
411
429
  method_type, connection, class_name, name, doc
412
430
  )
431
+
413
432
  # Check for any getattr/setattr overrides
414
433
  special_attributes = set(getattr_overrides.keys())
415
434
  special_attributes.update(set(setattr_overrides.keys()))