ob-metaflow 2.15.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.
- metaflow/__init__.py +10 -3
- metaflow/_vendor/imghdr/__init__.py +186 -0
- metaflow/_vendor/yaml/__init__.py +427 -0
- metaflow/_vendor/yaml/composer.py +139 -0
- metaflow/_vendor/yaml/constructor.py +748 -0
- metaflow/_vendor/yaml/cyaml.py +101 -0
- metaflow/_vendor/yaml/dumper.py +62 -0
- metaflow/_vendor/yaml/emitter.py +1137 -0
- metaflow/_vendor/yaml/error.py +75 -0
- metaflow/_vendor/yaml/events.py +86 -0
- metaflow/_vendor/yaml/loader.py +63 -0
- metaflow/_vendor/yaml/nodes.py +49 -0
- metaflow/_vendor/yaml/parser.py +589 -0
- metaflow/_vendor/yaml/reader.py +185 -0
- metaflow/_vendor/yaml/representer.py +389 -0
- metaflow/_vendor/yaml/resolver.py +227 -0
- metaflow/_vendor/yaml/scanner.py +1435 -0
- metaflow/_vendor/yaml/serializer.py +111 -0
- metaflow/_vendor/yaml/tokens.py +104 -0
- metaflow/cards.py +4 -0
- metaflow/cli.py +125 -21
- metaflow/cli_components/init_cmd.py +1 -0
- metaflow/cli_components/run_cmds.py +204 -40
- metaflow/cli_components/step_cmd.py +160 -4
- metaflow/client/__init__.py +1 -0
- metaflow/client/core.py +198 -130
- metaflow/client/filecache.py +59 -32
- metaflow/cmd/code/__init__.py +2 -1
- metaflow/cmd/develop/stub_generator.py +49 -18
- metaflow/cmd/develop/stubs.py +9 -27
- metaflow/cmd/make_wrapper.py +30 -0
- metaflow/datastore/__init__.py +1 -0
- metaflow/datastore/content_addressed_store.py +40 -9
- metaflow/datastore/datastore_set.py +10 -1
- metaflow/datastore/flow_datastore.py +124 -4
- metaflow/datastore/spin_datastore.py +91 -0
- metaflow/datastore/task_datastore.py +92 -6
- metaflow/debug.py +5 -0
- metaflow/decorators.py +331 -82
- metaflow/extension_support/__init__.py +414 -356
- metaflow/extension_support/_empty_file.py +2 -2
- metaflow/flowspec.py +322 -82
- metaflow/graph.py +178 -15
- metaflow/includefile.py +25 -3
- metaflow/lint.py +94 -3
- metaflow/meta_files.py +13 -0
- metaflow/metadata_provider/metadata.py +13 -2
- metaflow/metaflow_config.py +66 -4
- metaflow/metaflow_environment.py +91 -25
- metaflow/metaflow_profile.py +18 -0
- metaflow/metaflow_version.py +16 -1
- metaflow/package/__init__.py +673 -0
- metaflow/packaging_sys/__init__.py +880 -0
- metaflow/packaging_sys/backend.py +128 -0
- metaflow/packaging_sys/distribution_support.py +153 -0
- metaflow/packaging_sys/tar_backend.py +99 -0
- metaflow/packaging_sys/utils.py +54 -0
- metaflow/packaging_sys/v1.py +527 -0
- metaflow/parameters.py +6 -2
- metaflow/plugins/__init__.py +6 -0
- metaflow/plugins/airflow/airflow.py +11 -1
- metaflow/plugins/airflow/airflow_cli.py +16 -5
- metaflow/plugins/argo/argo_client.py +42 -20
- metaflow/plugins/argo/argo_events.py +6 -6
- metaflow/plugins/argo/argo_workflows.py +1023 -344
- metaflow/plugins/argo/argo_workflows_cli.py +396 -94
- metaflow/plugins/argo/argo_workflows_decorator.py +9 -0
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +75 -49
- metaflow/plugins/argo/capture_error.py +5 -2
- metaflow/plugins/argo/conditional_input_paths.py +35 -0
- metaflow/plugins/argo/exit_hooks.py +209 -0
- metaflow/plugins/argo/param_val.py +19 -0
- metaflow/plugins/aws/aws_client.py +6 -0
- metaflow/plugins/aws/aws_utils.py +33 -1
- metaflow/plugins/aws/batch/batch.py +72 -5
- metaflow/plugins/aws/batch/batch_cli.py +24 -3
- metaflow/plugins/aws/batch/batch_decorator.py +57 -6
- metaflow/plugins/aws/step_functions/step_functions.py +28 -3
- metaflow/plugins/aws/step_functions/step_functions_cli.py +49 -4
- metaflow/plugins/aws/step_functions/step_functions_deployer.py +3 -0
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +30 -0
- metaflow/plugins/cards/card_cli.py +20 -1
- metaflow/plugins/cards/card_creator.py +24 -1
- metaflow/plugins/cards/card_datastore.py +21 -49
- metaflow/plugins/cards/card_decorator.py +58 -6
- metaflow/plugins/cards/card_modules/basic.py +38 -9
- metaflow/plugins/cards/card_modules/bundle.css +1 -1
- metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
- metaflow/plugins/cards/card_modules/components.py +592 -3
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +34 -5
- metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
- metaflow/plugins/cards/card_modules/main.css +1 -0
- metaflow/plugins/cards/card_modules/main.js +56 -41
- metaflow/plugins/cards/card_modules/test_cards.py +22 -6
- metaflow/plugins/cards/component_serializer.py +1 -8
- metaflow/plugins/cards/metadata.py +22 -0
- metaflow/plugins/catch_decorator.py +9 -0
- metaflow/plugins/datastores/local_storage.py +12 -6
- metaflow/plugins/datastores/spin_storage.py +12 -0
- metaflow/plugins/datatools/s3/s3.py +49 -17
- metaflow/plugins/datatools/s3/s3op.py +113 -66
- metaflow/plugins/env_escape/client_modules.py +102 -72
- metaflow/plugins/events_decorator.py +127 -121
- metaflow/plugins/exit_hook/__init__.py +0 -0
- metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
- metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
- metaflow/plugins/kubernetes/kubernetes.py +12 -1
- metaflow/plugins/kubernetes/kubernetes_cli.py +11 -0
- metaflow/plugins/kubernetes/kubernetes_decorator.py +25 -6
- metaflow/plugins/kubernetes/kubernetes_job.py +12 -4
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +31 -30
- metaflow/plugins/metadata_providers/local.py +76 -82
- metaflow/plugins/metadata_providers/service.py +13 -9
- metaflow/plugins/metadata_providers/spin.py +16 -0
- metaflow/plugins/package_cli.py +36 -24
- metaflow/plugins/parallel_decorator.py +11 -2
- metaflow/plugins/parsers.py +16 -0
- metaflow/plugins/pypi/bootstrap.py +7 -1
- metaflow/plugins/pypi/conda_decorator.py +41 -82
- metaflow/plugins/pypi/conda_environment.py +14 -6
- metaflow/plugins/pypi/micromamba.py +9 -1
- metaflow/plugins/pypi/pip.py +41 -5
- metaflow/plugins/pypi/pypi_decorator.py +4 -4
- metaflow/plugins/pypi/utils.py +22 -0
- metaflow/plugins/secrets/__init__.py +3 -0
- metaflow/plugins/secrets/secrets_decorator.py +14 -178
- metaflow/plugins/secrets/secrets_func.py +49 -0
- metaflow/plugins/secrets/secrets_spec.py +101 -0
- metaflow/plugins/secrets/utils.py +74 -0
- metaflow/plugins/test_unbounded_foreach_decorator.py +2 -2
- metaflow/plugins/timeout_decorator.py +0 -1
- metaflow/plugins/uv/bootstrap.py +29 -1
- metaflow/plugins/uv/uv_environment.py +5 -3
- metaflow/pylint_wrapper.py +5 -1
- metaflow/runner/click_api.py +79 -26
- metaflow/runner/deployer.py +208 -6
- metaflow/runner/deployer_impl.py +32 -12
- metaflow/runner/metaflow_runner.py +266 -33
- metaflow/runner/subprocess_manager.py +21 -1
- metaflow/runner/utils.py +27 -16
- metaflow/runtime.py +660 -66
- metaflow/task.py +255 -26
- metaflow/user_configs/config_options.py +33 -21
- metaflow/user_configs/config_parameters.py +220 -58
- metaflow/user_decorators/__init__.py +0 -0
- metaflow/user_decorators/common.py +144 -0
- metaflow/user_decorators/mutable_flow.py +512 -0
- metaflow/user_decorators/mutable_step.py +424 -0
- metaflow/user_decorators/user_flow_decorator.py +264 -0
- metaflow/user_decorators/user_step_decorator.py +749 -0
- metaflow/util.py +197 -7
- metaflow/vendor.py +23 -7
- metaflow/version.py +1 -1
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Makefile +13 -2
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Tiltfile +107 -7
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/pick_services.sh +1 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/METADATA +2 -3
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/RECORD +162 -121
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
- metaflow/_vendor/v3_5/__init__.py +0 -1
- metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
- metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
- metaflow/_vendor/v3_5/zipp.py +0 -329
- metaflow/info_file.py +0 -25
- metaflow/package.py +0 -203
- metaflow/user_configs/config_decorators.py +0 -568
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +0 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/licenses/LICENSE +0 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
metaflow/__init__.py
CHANGED
|
@@ -104,7 +104,13 @@ from .flowspec import FlowSpec
|
|
|
104
104
|
from .parameters import Parameter, JSONTypeClass, JSONType
|
|
105
105
|
|
|
106
106
|
from .user_configs.config_parameters import Config, ConfigValue, config_expr
|
|
107
|
-
from .
|
|
107
|
+
from .user_decorators.user_step_decorator import (
|
|
108
|
+
UserStepDecorator,
|
|
109
|
+
StepMutator,
|
|
110
|
+
user_step_decorator,
|
|
111
|
+
USER_SKIP_STEP,
|
|
112
|
+
)
|
|
113
|
+
from .user_decorators.user_flow_decorator import FlowMutator
|
|
108
114
|
|
|
109
115
|
# data layer
|
|
110
116
|
# For historical reasons, we make metaflow.plugins.datatools accessible as
|
|
@@ -128,8 +134,8 @@ _import_tl_plugins(globals())
|
|
|
128
134
|
# this auto-generates decorator functions from Decorator objects
|
|
129
135
|
# in the top-level metaflow namespace
|
|
130
136
|
_import_plugin_decorators(globals())
|
|
131
|
-
# Setting card import for only python 3.
|
|
132
|
-
if sys.version_info[0] >= 3 and sys.version_info[1] >=
|
|
137
|
+
# Setting card import for only python 3.6
|
|
138
|
+
if sys.version_info[0] >= 3 and sys.version_info[1] >= 6:
|
|
133
139
|
from . import cards
|
|
134
140
|
|
|
135
141
|
# Client
|
|
@@ -140,6 +146,7 @@ from .client import (
|
|
|
140
146
|
metadata,
|
|
141
147
|
get_metadata,
|
|
142
148
|
default_metadata,
|
|
149
|
+
inspect_spin,
|
|
143
150
|
Metaflow,
|
|
144
151
|
Flow,
|
|
145
152
|
Run,
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Recognize image file formats based on their first few bytes."""
|
|
2
|
+
|
|
3
|
+
from os import PathLike
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
__all__ = ["what"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# python-deadlib: Replace deprecation warning not to raise exception
|
|
10
|
+
warnings.warn(
|
|
11
|
+
f"{__name__} was removed in Python 3.13. "
|
|
12
|
+
f"Please be aware that you are currently NOT using standard '{__name__}', "
|
|
13
|
+
f"but instead a separately installed 'standard-{__name__}'.",
|
|
14
|
+
DeprecationWarning, stacklevel=2
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
#-------------------------#
|
|
19
|
+
# Recognize image headers #
|
|
20
|
+
#-------------------------#
|
|
21
|
+
|
|
22
|
+
def what(file, h=None):
|
|
23
|
+
"""Return the type of image contained in a file or byte stream."""
|
|
24
|
+
f = None
|
|
25
|
+
try:
|
|
26
|
+
if h is None:
|
|
27
|
+
if isinstance(file, (str, PathLike)):
|
|
28
|
+
f = open(file, 'rb')
|
|
29
|
+
h = f.read(32)
|
|
30
|
+
else:
|
|
31
|
+
location = file.tell()
|
|
32
|
+
h = file.read(32)
|
|
33
|
+
file.seek(location)
|
|
34
|
+
for tf in tests:
|
|
35
|
+
res = tf(h, f)
|
|
36
|
+
if res:
|
|
37
|
+
return res
|
|
38
|
+
finally:
|
|
39
|
+
if f: f.close()
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
#---------------------------------#
|
|
44
|
+
# Subroutines per image file type #
|
|
45
|
+
#---------------------------------#
|
|
46
|
+
|
|
47
|
+
tests = []
|
|
48
|
+
|
|
49
|
+
def test_jpeg(h, f):
|
|
50
|
+
"""Test for JPEG data with JFIF or Exif markers; and raw JPEG."""
|
|
51
|
+
if h[6:10] in (b'JFIF', b'Exif'):
|
|
52
|
+
return 'jpeg'
|
|
53
|
+
elif h[:4] == b'\xff\xd8\xff\xdb':
|
|
54
|
+
return 'jpeg'
|
|
55
|
+
|
|
56
|
+
tests.append(test_jpeg)
|
|
57
|
+
|
|
58
|
+
def test_png(h, f):
|
|
59
|
+
"""Verify if the image is a PNG."""
|
|
60
|
+
if h.startswith(b'\211PNG\r\n\032\n'):
|
|
61
|
+
return 'png'
|
|
62
|
+
|
|
63
|
+
tests.append(test_png)
|
|
64
|
+
|
|
65
|
+
def test_gif(h, f):
|
|
66
|
+
"""Verify if the image is a GIF ('87 or '89 variants)."""
|
|
67
|
+
if h[:6] in (b'GIF87a', b'GIF89a'):
|
|
68
|
+
return 'gif'
|
|
69
|
+
|
|
70
|
+
tests.append(test_gif)
|
|
71
|
+
|
|
72
|
+
def test_tiff(h, f):
|
|
73
|
+
"""Verify if the image is a TIFF (can be in Motorola or Intel byte order)."""
|
|
74
|
+
if h[:2] in (b'MM', b'II'):
|
|
75
|
+
return 'tiff'
|
|
76
|
+
|
|
77
|
+
tests.append(test_tiff)
|
|
78
|
+
|
|
79
|
+
def test_rgb(h, f):
|
|
80
|
+
"""test for the SGI image library."""
|
|
81
|
+
if h.startswith(b'\001\332'):
|
|
82
|
+
return 'rgb'
|
|
83
|
+
|
|
84
|
+
tests.append(test_rgb)
|
|
85
|
+
|
|
86
|
+
def test_pbm(h, f):
|
|
87
|
+
"""Verify if the image is a PBM (portable bitmap)."""
|
|
88
|
+
if len(h) >= 3 and \
|
|
89
|
+
h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
|
|
90
|
+
return 'pbm'
|
|
91
|
+
|
|
92
|
+
tests.append(test_pbm)
|
|
93
|
+
|
|
94
|
+
def test_pgm(h, f):
|
|
95
|
+
"""Verify if the image is a PGM (portable graymap)."""
|
|
96
|
+
if len(h) >= 3 and \
|
|
97
|
+
h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
|
|
98
|
+
return 'pgm'
|
|
99
|
+
|
|
100
|
+
tests.append(test_pgm)
|
|
101
|
+
|
|
102
|
+
def test_ppm(h, f):
|
|
103
|
+
"""Verify if the image is a PPM (portable pixmap)."""
|
|
104
|
+
if len(h) >= 3 and \
|
|
105
|
+
h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
|
|
106
|
+
return 'ppm'
|
|
107
|
+
|
|
108
|
+
tests.append(test_ppm)
|
|
109
|
+
|
|
110
|
+
def test_rast(h, f):
|
|
111
|
+
"""test for the Sun raster file."""
|
|
112
|
+
if h.startswith(b'\x59\xA6\x6A\x95'):
|
|
113
|
+
return 'rast'
|
|
114
|
+
|
|
115
|
+
tests.append(test_rast)
|
|
116
|
+
|
|
117
|
+
def test_xbm(h, f):
|
|
118
|
+
"""Verify if the image is a X bitmap (X10 or X11)."""
|
|
119
|
+
if h.startswith(b'#define '):
|
|
120
|
+
return 'xbm'
|
|
121
|
+
|
|
122
|
+
tests.append(test_xbm)
|
|
123
|
+
|
|
124
|
+
def test_bmp(h, f):
|
|
125
|
+
"""Verify if the image is a BMP file."""
|
|
126
|
+
if h.startswith(b'BM'):
|
|
127
|
+
return 'bmp'
|
|
128
|
+
|
|
129
|
+
tests.append(test_bmp)
|
|
130
|
+
|
|
131
|
+
def test_webp(h, f):
|
|
132
|
+
"""Verify if the image is a WebP."""
|
|
133
|
+
if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
|
|
134
|
+
return 'webp'
|
|
135
|
+
|
|
136
|
+
tests.append(test_webp)
|
|
137
|
+
|
|
138
|
+
def test_exr(h, f):
|
|
139
|
+
"""verify is the image ia a OpenEXR fileOpenEXR."""
|
|
140
|
+
if h.startswith(b'\x76\x2f\x31\x01'):
|
|
141
|
+
return 'exr'
|
|
142
|
+
|
|
143
|
+
tests.append(test_exr)
|
|
144
|
+
|
|
145
|
+
#--------------------#
|
|
146
|
+
# Small test program #
|
|
147
|
+
#--------------------#
|
|
148
|
+
|
|
149
|
+
def test():
|
|
150
|
+
import sys
|
|
151
|
+
recursive = 0
|
|
152
|
+
if sys.argv[1:] and sys.argv[1] == '-r':
|
|
153
|
+
del sys.argv[1:2]
|
|
154
|
+
recursive = 1
|
|
155
|
+
try:
|
|
156
|
+
if sys.argv[1:]:
|
|
157
|
+
testall(sys.argv[1:], recursive, 1)
|
|
158
|
+
else:
|
|
159
|
+
testall(['.'], recursive, 1)
|
|
160
|
+
except KeyboardInterrupt:
|
|
161
|
+
sys.stderr.write('\n[Interrupted]\n')
|
|
162
|
+
sys.exit(1)
|
|
163
|
+
|
|
164
|
+
def testall(list, recursive, toplevel):
|
|
165
|
+
import sys
|
|
166
|
+
import os
|
|
167
|
+
for filename in list:
|
|
168
|
+
if os.path.isdir(filename):
|
|
169
|
+
print(filename + '/:', end=' ')
|
|
170
|
+
if recursive or toplevel:
|
|
171
|
+
print('recursing down:')
|
|
172
|
+
import glob
|
|
173
|
+
names = glob.glob(os.path.join(glob.escape(filename), '*'))
|
|
174
|
+
testall(names, recursive, 0)
|
|
175
|
+
else:
|
|
176
|
+
print('*** directory (use -r) ***')
|
|
177
|
+
else:
|
|
178
|
+
print(filename + ':', end=' ')
|
|
179
|
+
sys.stdout.flush()
|
|
180
|
+
try:
|
|
181
|
+
print(what(filename))
|
|
182
|
+
except OSError:
|
|
183
|
+
print('*** not found ***')
|
|
184
|
+
|
|
185
|
+
if __name__ == '__main__':
|
|
186
|
+
test()
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
|
|
2
|
+
from .error import *
|
|
3
|
+
|
|
4
|
+
from .tokens import *
|
|
5
|
+
from .events import *
|
|
6
|
+
from .nodes import *
|
|
7
|
+
|
|
8
|
+
from .loader import *
|
|
9
|
+
from .dumper import *
|
|
10
|
+
|
|
11
|
+
__version__ = '5.3.1'
|
|
12
|
+
try:
|
|
13
|
+
from .cyaml import *
|
|
14
|
+
__with_libyaml__ = True
|
|
15
|
+
except ImportError:
|
|
16
|
+
__with_libyaml__ = False
|
|
17
|
+
|
|
18
|
+
import io
|
|
19
|
+
|
|
20
|
+
#------------------------------------------------------------------------------
|
|
21
|
+
# Warnings control
|
|
22
|
+
#------------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
# 'Global' warnings state:
|
|
25
|
+
_warnings_enabled = {
|
|
26
|
+
'YAMLLoadWarning': True,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Get or set global warnings' state
|
|
30
|
+
def warnings(settings=None):
|
|
31
|
+
if settings is None:
|
|
32
|
+
return _warnings_enabled
|
|
33
|
+
|
|
34
|
+
if type(settings) is dict:
|
|
35
|
+
for key in settings:
|
|
36
|
+
if key in _warnings_enabled:
|
|
37
|
+
_warnings_enabled[key] = settings[key]
|
|
38
|
+
|
|
39
|
+
# Warn when load() is called without Loader=...
|
|
40
|
+
class YAMLLoadWarning(RuntimeWarning):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def load_warning(method):
|
|
44
|
+
if _warnings_enabled['YAMLLoadWarning'] is False:
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
import warnings
|
|
48
|
+
|
|
49
|
+
message = (
|
|
50
|
+
"calling yaml.%s() without Loader=... is deprecated, as the "
|
|
51
|
+
"default Loader is unsafe. Please read "
|
|
52
|
+
"https://msg.pyyaml.org/load for full details."
|
|
53
|
+
) % method
|
|
54
|
+
|
|
55
|
+
warnings.warn(message, YAMLLoadWarning, stacklevel=3)
|
|
56
|
+
|
|
57
|
+
#------------------------------------------------------------------------------
|
|
58
|
+
def scan(stream, Loader=Loader):
|
|
59
|
+
"""
|
|
60
|
+
Scan a YAML stream and produce scanning tokens.
|
|
61
|
+
"""
|
|
62
|
+
loader = Loader(stream)
|
|
63
|
+
try:
|
|
64
|
+
while loader.check_token():
|
|
65
|
+
yield loader.get_token()
|
|
66
|
+
finally:
|
|
67
|
+
loader.dispose()
|
|
68
|
+
|
|
69
|
+
def parse(stream, Loader=Loader):
|
|
70
|
+
"""
|
|
71
|
+
Parse a YAML stream and produce parsing events.
|
|
72
|
+
"""
|
|
73
|
+
loader = Loader(stream)
|
|
74
|
+
try:
|
|
75
|
+
while loader.check_event():
|
|
76
|
+
yield loader.get_event()
|
|
77
|
+
finally:
|
|
78
|
+
loader.dispose()
|
|
79
|
+
|
|
80
|
+
def compose(stream, Loader=Loader):
|
|
81
|
+
"""
|
|
82
|
+
Parse the first YAML document in a stream
|
|
83
|
+
and produce the corresponding representation tree.
|
|
84
|
+
"""
|
|
85
|
+
loader = Loader(stream)
|
|
86
|
+
try:
|
|
87
|
+
return loader.get_single_node()
|
|
88
|
+
finally:
|
|
89
|
+
loader.dispose()
|
|
90
|
+
|
|
91
|
+
def compose_all(stream, Loader=Loader):
|
|
92
|
+
"""
|
|
93
|
+
Parse all YAML documents in a stream
|
|
94
|
+
and produce corresponding representation trees.
|
|
95
|
+
"""
|
|
96
|
+
loader = Loader(stream)
|
|
97
|
+
try:
|
|
98
|
+
while loader.check_node():
|
|
99
|
+
yield loader.get_node()
|
|
100
|
+
finally:
|
|
101
|
+
loader.dispose()
|
|
102
|
+
|
|
103
|
+
def load(stream, Loader=None):
|
|
104
|
+
"""
|
|
105
|
+
Parse the first YAML document in a stream
|
|
106
|
+
and produce the corresponding Python object.
|
|
107
|
+
"""
|
|
108
|
+
if Loader is None:
|
|
109
|
+
load_warning('load')
|
|
110
|
+
Loader = FullLoader
|
|
111
|
+
|
|
112
|
+
loader = Loader(stream)
|
|
113
|
+
try:
|
|
114
|
+
return loader.get_single_data()
|
|
115
|
+
finally:
|
|
116
|
+
loader.dispose()
|
|
117
|
+
|
|
118
|
+
def load_all(stream, Loader=None):
|
|
119
|
+
"""
|
|
120
|
+
Parse all YAML documents in a stream
|
|
121
|
+
and produce corresponding Python objects.
|
|
122
|
+
"""
|
|
123
|
+
if Loader is None:
|
|
124
|
+
load_warning('load_all')
|
|
125
|
+
Loader = FullLoader
|
|
126
|
+
|
|
127
|
+
loader = Loader(stream)
|
|
128
|
+
try:
|
|
129
|
+
while loader.check_data():
|
|
130
|
+
yield loader.get_data()
|
|
131
|
+
finally:
|
|
132
|
+
loader.dispose()
|
|
133
|
+
|
|
134
|
+
def full_load(stream):
|
|
135
|
+
"""
|
|
136
|
+
Parse the first YAML document in a stream
|
|
137
|
+
and produce the corresponding Python object.
|
|
138
|
+
|
|
139
|
+
Resolve all tags except those known to be
|
|
140
|
+
unsafe on untrusted input.
|
|
141
|
+
"""
|
|
142
|
+
return load(stream, FullLoader)
|
|
143
|
+
|
|
144
|
+
def full_load_all(stream):
|
|
145
|
+
"""
|
|
146
|
+
Parse all YAML documents in a stream
|
|
147
|
+
and produce corresponding Python objects.
|
|
148
|
+
|
|
149
|
+
Resolve all tags except those known to be
|
|
150
|
+
unsafe on untrusted input.
|
|
151
|
+
"""
|
|
152
|
+
return load_all(stream, FullLoader)
|
|
153
|
+
|
|
154
|
+
def safe_load(stream):
|
|
155
|
+
"""
|
|
156
|
+
Parse the first YAML document in a stream
|
|
157
|
+
and produce the corresponding Python object.
|
|
158
|
+
|
|
159
|
+
Resolve only basic YAML tags. This is known
|
|
160
|
+
to be safe for untrusted input.
|
|
161
|
+
"""
|
|
162
|
+
return load(stream, SafeLoader)
|
|
163
|
+
|
|
164
|
+
def safe_load_all(stream):
|
|
165
|
+
"""
|
|
166
|
+
Parse all YAML documents in a stream
|
|
167
|
+
and produce corresponding Python objects.
|
|
168
|
+
|
|
169
|
+
Resolve only basic YAML tags. This is known
|
|
170
|
+
to be safe for untrusted input.
|
|
171
|
+
"""
|
|
172
|
+
return load_all(stream, SafeLoader)
|
|
173
|
+
|
|
174
|
+
def unsafe_load(stream):
|
|
175
|
+
"""
|
|
176
|
+
Parse the first YAML document in a stream
|
|
177
|
+
and produce the corresponding Python object.
|
|
178
|
+
|
|
179
|
+
Resolve all tags, even those known to be
|
|
180
|
+
unsafe on untrusted input.
|
|
181
|
+
"""
|
|
182
|
+
return load(stream, UnsafeLoader)
|
|
183
|
+
|
|
184
|
+
def unsafe_load_all(stream):
|
|
185
|
+
"""
|
|
186
|
+
Parse all YAML documents in a stream
|
|
187
|
+
and produce corresponding Python objects.
|
|
188
|
+
|
|
189
|
+
Resolve all tags, even those known to be
|
|
190
|
+
unsafe on untrusted input.
|
|
191
|
+
"""
|
|
192
|
+
return load_all(stream, UnsafeLoader)
|
|
193
|
+
|
|
194
|
+
def emit(events, stream=None, Dumper=Dumper,
|
|
195
|
+
canonical=None, indent=None, width=None,
|
|
196
|
+
allow_unicode=None, line_break=None):
|
|
197
|
+
"""
|
|
198
|
+
Emit YAML parsing events into a stream.
|
|
199
|
+
If stream is None, return the produced string instead.
|
|
200
|
+
"""
|
|
201
|
+
getvalue = None
|
|
202
|
+
if stream is None:
|
|
203
|
+
stream = io.StringIO()
|
|
204
|
+
getvalue = stream.getvalue
|
|
205
|
+
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
|
206
|
+
allow_unicode=allow_unicode, line_break=line_break)
|
|
207
|
+
try:
|
|
208
|
+
for event in events:
|
|
209
|
+
dumper.emit(event)
|
|
210
|
+
finally:
|
|
211
|
+
dumper.dispose()
|
|
212
|
+
if getvalue:
|
|
213
|
+
return getvalue()
|
|
214
|
+
|
|
215
|
+
def serialize_all(nodes, stream=None, Dumper=Dumper,
|
|
216
|
+
canonical=None, indent=None, width=None,
|
|
217
|
+
allow_unicode=None, line_break=None,
|
|
218
|
+
encoding=None, explicit_start=None, explicit_end=None,
|
|
219
|
+
version=None, tags=None):
|
|
220
|
+
"""
|
|
221
|
+
Serialize a sequence of representation trees into a YAML stream.
|
|
222
|
+
If stream is None, return the produced string instead.
|
|
223
|
+
"""
|
|
224
|
+
getvalue = None
|
|
225
|
+
if stream is None:
|
|
226
|
+
if encoding is None:
|
|
227
|
+
stream = io.StringIO()
|
|
228
|
+
else:
|
|
229
|
+
stream = io.BytesIO()
|
|
230
|
+
getvalue = stream.getvalue
|
|
231
|
+
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
|
232
|
+
allow_unicode=allow_unicode, line_break=line_break,
|
|
233
|
+
encoding=encoding, version=version, tags=tags,
|
|
234
|
+
explicit_start=explicit_start, explicit_end=explicit_end)
|
|
235
|
+
try:
|
|
236
|
+
dumper.open()
|
|
237
|
+
for node in nodes:
|
|
238
|
+
dumper.serialize(node)
|
|
239
|
+
dumper.close()
|
|
240
|
+
finally:
|
|
241
|
+
dumper.dispose()
|
|
242
|
+
if getvalue:
|
|
243
|
+
return getvalue()
|
|
244
|
+
|
|
245
|
+
def serialize(node, stream=None, Dumper=Dumper, **kwds):
|
|
246
|
+
"""
|
|
247
|
+
Serialize a representation tree into a YAML stream.
|
|
248
|
+
If stream is None, return the produced string instead.
|
|
249
|
+
"""
|
|
250
|
+
return serialize_all([node], stream, Dumper=Dumper, **kwds)
|
|
251
|
+
|
|
252
|
+
def dump_all(documents, stream=None, Dumper=Dumper,
|
|
253
|
+
default_style=None, default_flow_style=False,
|
|
254
|
+
canonical=None, indent=None, width=None,
|
|
255
|
+
allow_unicode=None, line_break=None,
|
|
256
|
+
encoding=None, explicit_start=None, explicit_end=None,
|
|
257
|
+
version=None, tags=None, sort_keys=True):
|
|
258
|
+
"""
|
|
259
|
+
Serialize a sequence of Python objects into a YAML stream.
|
|
260
|
+
If stream is None, return the produced string instead.
|
|
261
|
+
"""
|
|
262
|
+
getvalue = None
|
|
263
|
+
if stream is None:
|
|
264
|
+
if encoding is None:
|
|
265
|
+
stream = io.StringIO()
|
|
266
|
+
else:
|
|
267
|
+
stream = io.BytesIO()
|
|
268
|
+
getvalue = stream.getvalue
|
|
269
|
+
dumper = Dumper(stream, default_style=default_style,
|
|
270
|
+
default_flow_style=default_flow_style,
|
|
271
|
+
canonical=canonical, indent=indent, width=width,
|
|
272
|
+
allow_unicode=allow_unicode, line_break=line_break,
|
|
273
|
+
encoding=encoding, version=version, tags=tags,
|
|
274
|
+
explicit_start=explicit_start, explicit_end=explicit_end, sort_keys=sort_keys)
|
|
275
|
+
try:
|
|
276
|
+
dumper.open()
|
|
277
|
+
for data in documents:
|
|
278
|
+
dumper.represent(data)
|
|
279
|
+
dumper.close()
|
|
280
|
+
finally:
|
|
281
|
+
dumper.dispose()
|
|
282
|
+
if getvalue:
|
|
283
|
+
return getvalue()
|
|
284
|
+
|
|
285
|
+
def dump(data, stream=None, Dumper=Dumper, **kwds):
|
|
286
|
+
"""
|
|
287
|
+
Serialize a Python object into a YAML stream.
|
|
288
|
+
If stream is None, return the produced string instead.
|
|
289
|
+
"""
|
|
290
|
+
return dump_all([data], stream, Dumper=Dumper, **kwds)
|
|
291
|
+
|
|
292
|
+
def safe_dump_all(documents, stream=None, **kwds):
|
|
293
|
+
"""
|
|
294
|
+
Serialize a sequence of Python objects into a YAML stream.
|
|
295
|
+
Produce only basic YAML tags.
|
|
296
|
+
If stream is None, return the produced string instead.
|
|
297
|
+
"""
|
|
298
|
+
return dump_all(documents, stream, Dumper=SafeDumper, **kwds)
|
|
299
|
+
|
|
300
|
+
def safe_dump(data, stream=None, **kwds):
|
|
301
|
+
"""
|
|
302
|
+
Serialize a Python object into a YAML stream.
|
|
303
|
+
Produce only basic YAML tags.
|
|
304
|
+
If stream is None, return the produced string instead.
|
|
305
|
+
"""
|
|
306
|
+
return dump_all([data], stream, Dumper=SafeDumper, **kwds)
|
|
307
|
+
|
|
308
|
+
def add_implicit_resolver(tag, regexp, first=None,
|
|
309
|
+
Loader=None, Dumper=Dumper):
|
|
310
|
+
"""
|
|
311
|
+
Add an implicit scalar detector.
|
|
312
|
+
If an implicit scalar value matches the given regexp,
|
|
313
|
+
the corresponding tag is assigned to the scalar.
|
|
314
|
+
first is a sequence of possible initial characters or None.
|
|
315
|
+
"""
|
|
316
|
+
if Loader is None:
|
|
317
|
+
loader.Loader.add_implicit_resolver(tag, regexp, first)
|
|
318
|
+
loader.FullLoader.add_implicit_resolver(tag, regexp, first)
|
|
319
|
+
loader.UnsafeLoader.add_implicit_resolver(tag, regexp, first)
|
|
320
|
+
else:
|
|
321
|
+
Loader.add_implicit_resolver(tag, regexp, first)
|
|
322
|
+
Dumper.add_implicit_resolver(tag, regexp, first)
|
|
323
|
+
|
|
324
|
+
def add_path_resolver(tag, path, kind=None, Loader=None, Dumper=Dumper):
|
|
325
|
+
"""
|
|
326
|
+
Add a path based resolver for the given tag.
|
|
327
|
+
A path is a list of keys that forms a path
|
|
328
|
+
to a node in the representation tree.
|
|
329
|
+
Keys can be string values, integers, or None.
|
|
330
|
+
"""
|
|
331
|
+
if Loader is None:
|
|
332
|
+
loader.Loader.add_path_resolver(tag, path, kind)
|
|
333
|
+
loader.FullLoader.add_path_resolver(tag, path, kind)
|
|
334
|
+
loader.UnsafeLoader.add_path_resolver(tag, path, kind)
|
|
335
|
+
else:
|
|
336
|
+
Loader.add_path_resolver(tag, path, kind)
|
|
337
|
+
Dumper.add_path_resolver(tag, path, kind)
|
|
338
|
+
|
|
339
|
+
def add_constructor(tag, constructor, Loader=None):
|
|
340
|
+
"""
|
|
341
|
+
Add a constructor for the given tag.
|
|
342
|
+
Constructor is a function that accepts a Loader instance
|
|
343
|
+
and a node object and produces the corresponding Python object.
|
|
344
|
+
"""
|
|
345
|
+
if Loader is None:
|
|
346
|
+
loader.Loader.add_constructor(tag, constructor)
|
|
347
|
+
loader.FullLoader.add_constructor(tag, constructor)
|
|
348
|
+
loader.UnsafeLoader.add_constructor(tag, constructor)
|
|
349
|
+
else:
|
|
350
|
+
Loader.add_constructor(tag, constructor)
|
|
351
|
+
|
|
352
|
+
def add_multi_constructor(tag_prefix, multi_constructor, Loader=None):
|
|
353
|
+
"""
|
|
354
|
+
Add a multi-constructor for the given tag prefix.
|
|
355
|
+
Multi-constructor is called for a node if its tag starts with tag_prefix.
|
|
356
|
+
Multi-constructor accepts a Loader instance, a tag suffix,
|
|
357
|
+
and a node object and produces the corresponding Python object.
|
|
358
|
+
"""
|
|
359
|
+
if Loader is None:
|
|
360
|
+
loader.Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
361
|
+
loader.FullLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
362
|
+
loader.UnsafeLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
363
|
+
else:
|
|
364
|
+
Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
365
|
+
|
|
366
|
+
def add_representer(data_type, representer, Dumper=Dumper):
|
|
367
|
+
"""
|
|
368
|
+
Add a representer for the given type.
|
|
369
|
+
Representer is a function accepting a Dumper instance
|
|
370
|
+
and an instance of the given data type
|
|
371
|
+
and producing the corresponding representation node.
|
|
372
|
+
"""
|
|
373
|
+
Dumper.add_representer(data_type, representer)
|
|
374
|
+
|
|
375
|
+
def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
|
|
376
|
+
"""
|
|
377
|
+
Add a representer for the given type.
|
|
378
|
+
Multi-representer is a function accepting a Dumper instance
|
|
379
|
+
and an instance of the given data type or subtype
|
|
380
|
+
and producing the corresponding representation node.
|
|
381
|
+
"""
|
|
382
|
+
Dumper.add_multi_representer(data_type, multi_representer)
|
|
383
|
+
|
|
384
|
+
class YAMLObjectMetaclass(type):
|
|
385
|
+
"""
|
|
386
|
+
The metaclass for YAMLObject.
|
|
387
|
+
"""
|
|
388
|
+
def __init__(cls, name, bases, kwds):
|
|
389
|
+
super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
|
|
390
|
+
if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
|
|
391
|
+
if isinstance(cls.yaml_loader, list):
|
|
392
|
+
for loader in cls.yaml_loader:
|
|
393
|
+
loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
|
394
|
+
else:
|
|
395
|
+
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
|
396
|
+
|
|
397
|
+
cls.yaml_dumper.add_representer(cls, cls.to_yaml)
|
|
398
|
+
|
|
399
|
+
class YAMLObject(metaclass=YAMLObjectMetaclass):
|
|
400
|
+
"""
|
|
401
|
+
An object that can dump itself to a YAML stream
|
|
402
|
+
and load itself from a YAML stream.
|
|
403
|
+
"""
|
|
404
|
+
|
|
405
|
+
__slots__ = () # no direct instantiation, so allow immutable subclasses
|
|
406
|
+
|
|
407
|
+
yaml_loader = [Loader, FullLoader, UnsafeLoader]
|
|
408
|
+
yaml_dumper = Dumper
|
|
409
|
+
|
|
410
|
+
yaml_tag = None
|
|
411
|
+
yaml_flow_style = None
|
|
412
|
+
|
|
413
|
+
@classmethod
|
|
414
|
+
def from_yaml(cls, loader, node):
|
|
415
|
+
"""
|
|
416
|
+
Convert a representation node to a Python object.
|
|
417
|
+
"""
|
|
418
|
+
return loader.construct_yaml_object(node, cls)
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def to_yaml(cls, dumper, data):
|
|
422
|
+
"""
|
|
423
|
+
Convert a Python object to a representation node.
|
|
424
|
+
"""
|
|
425
|
+
return dumper.represent_yaml_object(cls.yaml_tag, data, cls,
|
|
426
|
+
flow_style=cls.yaml_flow_style)
|
|
427
|
+
|