tensorbored 2.21.0rc1769983804__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 (271) hide show
  1. tensorbored/__init__.py +112 -0
  2. tensorbored/_vendor/__init__.py +0 -0
  3. tensorbored/_vendor/bleach/__init__.py +125 -0
  4. tensorbored/_vendor/bleach/_vendor/__init__.py +0 -0
  5. tensorbored/_vendor/bleach/_vendor/html5lib/__init__.py +35 -0
  6. tensorbored/_vendor/bleach/_vendor/html5lib/_ihatexml.py +289 -0
  7. tensorbored/_vendor/bleach/_vendor/html5lib/_inputstream.py +918 -0
  8. tensorbored/_vendor/bleach/_vendor/html5lib/_tokenizer.py +1735 -0
  9. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/__init__.py +5 -0
  10. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/_base.py +40 -0
  11. tensorbored/_vendor/bleach/_vendor/html5lib/_trie/py.py +67 -0
  12. tensorbored/_vendor/bleach/_vendor/html5lib/_utils.py +159 -0
  13. tensorbored/_vendor/bleach/_vendor/html5lib/constants.py +2946 -0
  14. tensorbored/_vendor/bleach/_vendor/html5lib/filters/__init__.py +0 -0
  15. tensorbored/_vendor/bleach/_vendor/html5lib/filters/alphabeticalattributes.py +29 -0
  16. tensorbored/_vendor/bleach/_vendor/html5lib/filters/base.py +12 -0
  17. tensorbored/_vendor/bleach/_vendor/html5lib/filters/inject_meta_charset.py +73 -0
  18. tensorbored/_vendor/bleach/_vendor/html5lib/filters/lint.py +93 -0
  19. tensorbored/_vendor/bleach/_vendor/html5lib/filters/optionaltags.py +207 -0
  20. tensorbored/_vendor/bleach/_vendor/html5lib/filters/sanitizer.py +916 -0
  21. tensorbored/_vendor/bleach/_vendor/html5lib/filters/whitespace.py +38 -0
  22. tensorbored/_vendor/bleach/_vendor/html5lib/html5parser.py +2795 -0
  23. tensorbored/_vendor/bleach/_vendor/html5lib/serializer.py +409 -0
  24. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/__init__.py +30 -0
  25. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/genshi.py +54 -0
  26. tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/sax.py +50 -0
  27. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/__init__.py +88 -0
  28. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/base.py +417 -0
  29. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/dom.py +239 -0
  30. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree.py +343 -0
  31. tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree_lxml.py +392 -0
  32. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/__init__.py +154 -0
  33. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/base.py +252 -0
  34. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/dom.py +43 -0
  35. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree.py +131 -0
  36. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree_lxml.py +215 -0
  37. tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/genshi.py +69 -0
  38. tensorbored/_vendor/bleach/_vendor/parse.py +1078 -0
  39. tensorbored/_vendor/bleach/callbacks.py +32 -0
  40. tensorbored/_vendor/bleach/html5lib_shim.py +757 -0
  41. tensorbored/_vendor/bleach/linkifier.py +633 -0
  42. tensorbored/_vendor/bleach/parse_shim.py +1 -0
  43. tensorbored/_vendor/bleach/sanitizer.py +638 -0
  44. tensorbored/_vendor/bleach/six_shim.py +19 -0
  45. tensorbored/_vendor/webencodings/__init__.py +342 -0
  46. tensorbored/_vendor/webencodings/labels.py +231 -0
  47. tensorbored/_vendor/webencodings/mklabels.py +59 -0
  48. tensorbored/_vendor/webencodings/x_user_defined.py +325 -0
  49. tensorbored/assets.py +36 -0
  50. tensorbored/auth.py +102 -0
  51. tensorbored/backend/__init__.py +0 -0
  52. tensorbored/backend/application.py +604 -0
  53. tensorbored/backend/auth_context_middleware.py +38 -0
  54. tensorbored/backend/client_feature_flags.py +113 -0
  55. tensorbored/backend/empty_path_redirect.py +46 -0
  56. tensorbored/backend/event_processing/__init__.py +0 -0
  57. tensorbored/backend/event_processing/data_ingester.py +276 -0
  58. tensorbored/backend/event_processing/data_provider.py +535 -0
  59. tensorbored/backend/event_processing/directory_loader.py +142 -0
  60. tensorbored/backend/event_processing/directory_watcher.py +272 -0
  61. tensorbored/backend/event_processing/event_accumulator.py +950 -0
  62. tensorbored/backend/event_processing/event_file_inspector.py +463 -0
  63. tensorbored/backend/event_processing/event_file_loader.py +292 -0
  64. tensorbored/backend/event_processing/event_multiplexer.py +521 -0
  65. tensorbored/backend/event_processing/event_util.py +68 -0
  66. tensorbored/backend/event_processing/io_wrapper.py +223 -0
  67. tensorbored/backend/event_processing/plugin_asset_util.py +104 -0
  68. tensorbored/backend/event_processing/plugin_event_accumulator.py +721 -0
  69. tensorbored/backend/event_processing/plugin_event_multiplexer.py +522 -0
  70. tensorbored/backend/event_processing/reservoir.py +266 -0
  71. tensorbored/backend/event_processing/tag_types.py +29 -0
  72. tensorbored/backend/experiment_id.py +71 -0
  73. tensorbored/backend/experimental_plugin.py +51 -0
  74. tensorbored/backend/http_util.py +263 -0
  75. tensorbored/backend/json_util.py +70 -0
  76. tensorbored/backend/path_prefix.py +67 -0
  77. tensorbored/backend/process_graph.py +74 -0
  78. tensorbored/backend/security_validator.py +202 -0
  79. tensorbored/compat/__init__.py +69 -0
  80. tensorbored/compat/proto/__init__.py +0 -0
  81. tensorbored/compat/proto/allocation_description_pb2.py +35 -0
  82. tensorbored/compat/proto/api_def_pb2.py +82 -0
  83. tensorbored/compat/proto/attr_value_pb2.py +80 -0
  84. tensorbored/compat/proto/cluster_pb2.py +58 -0
  85. tensorbored/compat/proto/config_pb2.py +271 -0
  86. tensorbored/compat/proto/coordination_config_pb2.py +45 -0
  87. tensorbored/compat/proto/cost_graph_pb2.py +87 -0
  88. tensorbored/compat/proto/cpp_shape_inference_pb2.py +70 -0
  89. tensorbored/compat/proto/debug_pb2.py +65 -0
  90. tensorbored/compat/proto/event_pb2.py +149 -0
  91. tensorbored/compat/proto/full_type_pb2.py +74 -0
  92. tensorbored/compat/proto/function_pb2.py +157 -0
  93. tensorbored/compat/proto/graph_debug_info_pb2.py +111 -0
  94. tensorbored/compat/proto/graph_pb2.py +41 -0
  95. tensorbored/compat/proto/histogram_pb2.py +39 -0
  96. tensorbored/compat/proto/meta_graph_pb2.py +254 -0
  97. tensorbored/compat/proto/node_def_pb2.py +61 -0
  98. tensorbored/compat/proto/op_def_pb2.py +81 -0
  99. tensorbored/compat/proto/resource_handle_pb2.py +48 -0
  100. tensorbored/compat/proto/rewriter_config_pb2.py +93 -0
  101. tensorbored/compat/proto/rpc_options_pb2.py +35 -0
  102. tensorbored/compat/proto/saved_object_graph_pb2.py +193 -0
  103. tensorbored/compat/proto/saver_pb2.py +38 -0
  104. tensorbored/compat/proto/step_stats_pb2.py +116 -0
  105. tensorbored/compat/proto/struct_pb2.py +144 -0
  106. tensorbored/compat/proto/summary_pb2.py +111 -0
  107. tensorbored/compat/proto/tensor_description_pb2.py +38 -0
  108. tensorbored/compat/proto/tensor_pb2.py +68 -0
  109. tensorbored/compat/proto/tensor_shape_pb2.py +46 -0
  110. tensorbored/compat/proto/tfprof_log_pb2.py +307 -0
  111. tensorbored/compat/proto/trackable_object_graph_pb2.py +90 -0
  112. tensorbored/compat/proto/types_pb2.py +105 -0
  113. tensorbored/compat/proto/variable_pb2.py +62 -0
  114. tensorbored/compat/proto/verifier_config_pb2.py +38 -0
  115. tensorbored/compat/proto/versions_pb2.py +35 -0
  116. tensorbored/compat/tensorflow_stub/__init__.py +38 -0
  117. tensorbored/compat/tensorflow_stub/app.py +124 -0
  118. tensorbored/compat/tensorflow_stub/compat/__init__.py +131 -0
  119. tensorbored/compat/tensorflow_stub/compat/v1/__init__.py +20 -0
  120. tensorbored/compat/tensorflow_stub/dtypes.py +692 -0
  121. tensorbored/compat/tensorflow_stub/error_codes.py +169 -0
  122. tensorbored/compat/tensorflow_stub/errors.py +507 -0
  123. tensorbored/compat/tensorflow_stub/flags.py +124 -0
  124. tensorbored/compat/tensorflow_stub/io/__init__.py +17 -0
  125. tensorbored/compat/tensorflow_stub/io/gfile.py +1011 -0
  126. tensorbored/compat/tensorflow_stub/pywrap_tensorflow.py +285 -0
  127. tensorbored/compat/tensorflow_stub/tensor_shape.py +1035 -0
  128. tensorbored/context.py +129 -0
  129. tensorbored/data/__init__.py +0 -0
  130. tensorbored/data/grpc_provider.py +365 -0
  131. tensorbored/data/ingester.py +46 -0
  132. tensorbored/data/proto/__init__.py +0 -0
  133. tensorbored/data/proto/data_provider_pb2.py +517 -0
  134. tensorbored/data/proto/data_provider_pb2_grpc.py +374 -0
  135. tensorbored/data/provider.py +1365 -0
  136. tensorbored/data/server_ingester.py +301 -0
  137. tensorbored/data_compat.py +159 -0
  138. tensorbored/dataclass_compat.py +224 -0
  139. tensorbored/default.py +124 -0
  140. tensorbored/errors.py +130 -0
  141. tensorbored/lazy.py +99 -0
  142. tensorbored/main.py +48 -0
  143. tensorbored/main_lib.py +62 -0
  144. tensorbored/manager.py +487 -0
  145. tensorbored/notebook.py +441 -0
  146. tensorbored/plugin_util.py +266 -0
  147. tensorbored/plugins/__init__.py +0 -0
  148. tensorbored/plugins/audio/__init__.py +0 -0
  149. tensorbored/plugins/audio/audio_plugin.py +229 -0
  150. tensorbored/plugins/audio/metadata.py +69 -0
  151. tensorbored/plugins/audio/plugin_data_pb2.py +37 -0
  152. tensorbored/plugins/audio/summary.py +230 -0
  153. tensorbored/plugins/audio/summary_v2.py +124 -0
  154. tensorbored/plugins/base_plugin.py +367 -0
  155. tensorbored/plugins/core/__init__.py +0 -0
  156. tensorbored/plugins/core/core_plugin.py +981 -0
  157. tensorbored/plugins/custom_scalar/__init__.py +0 -0
  158. tensorbored/plugins/custom_scalar/custom_scalars_plugin.py +320 -0
  159. tensorbored/plugins/custom_scalar/layout_pb2.py +85 -0
  160. tensorbored/plugins/custom_scalar/metadata.py +35 -0
  161. tensorbored/plugins/custom_scalar/summary.py +79 -0
  162. tensorbored/plugins/debugger_v2/__init__.py +0 -0
  163. tensorbored/plugins/debugger_v2/debug_data_multiplexer.py +631 -0
  164. tensorbored/plugins/debugger_v2/debug_data_provider.py +634 -0
  165. tensorbored/plugins/debugger_v2/debugger_v2_plugin.py +504 -0
  166. tensorbored/plugins/distribution/__init__.py +0 -0
  167. tensorbored/plugins/distribution/compressor.py +158 -0
  168. tensorbored/plugins/distribution/distributions_plugin.py +116 -0
  169. tensorbored/plugins/distribution/metadata.py +19 -0
  170. tensorbored/plugins/graph/__init__.py +0 -0
  171. tensorbored/plugins/graph/graph_util.py +129 -0
  172. tensorbored/plugins/graph/graphs_plugin.py +336 -0
  173. tensorbored/plugins/graph/keras_util.py +328 -0
  174. tensorbored/plugins/graph/metadata.py +42 -0
  175. tensorbored/plugins/histogram/__init__.py +0 -0
  176. tensorbored/plugins/histogram/histograms_plugin.py +144 -0
  177. tensorbored/plugins/histogram/metadata.py +63 -0
  178. tensorbored/plugins/histogram/plugin_data_pb2.py +34 -0
  179. tensorbored/plugins/histogram/summary.py +234 -0
  180. tensorbored/plugins/histogram/summary_v2.py +292 -0
  181. tensorbored/plugins/hparams/__init__.py +14 -0
  182. tensorbored/plugins/hparams/_keras.py +93 -0
  183. tensorbored/plugins/hparams/api.py +130 -0
  184. tensorbored/plugins/hparams/api_pb2.py +208 -0
  185. tensorbored/plugins/hparams/backend_context.py +606 -0
  186. tensorbored/plugins/hparams/download_data.py +158 -0
  187. tensorbored/plugins/hparams/error.py +26 -0
  188. tensorbored/plugins/hparams/get_experiment.py +71 -0
  189. tensorbored/plugins/hparams/hparams_plugin.py +206 -0
  190. tensorbored/plugins/hparams/hparams_util_pb2.py +69 -0
  191. tensorbored/plugins/hparams/json_format_compat.py +38 -0
  192. tensorbored/plugins/hparams/list_metric_evals.py +57 -0
  193. tensorbored/plugins/hparams/list_session_groups.py +1040 -0
  194. tensorbored/plugins/hparams/metadata.py +125 -0
  195. tensorbored/plugins/hparams/metrics.py +41 -0
  196. tensorbored/plugins/hparams/plugin_data_pb2.py +69 -0
  197. tensorbored/plugins/hparams/summary.py +205 -0
  198. tensorbored/plugins/hparams/summary_v2.py +597 -0
  199. tensorbored/plugins/image/__init__.py +0 -0
  200. tensorbored/plugins/image/images_plugin.py +232 -0
  201. tensorbored/plugins/image/metadata.py +65 -0
  202. tensorbored/plugins/image/plugin_data_pb2.py +34 -0
  203. tensorbored/plugins/image/summary.py +159 -0
  204. tensorbored/plugins/image/summary_v2.py +130 -0
  205. tensorbored/plugins/mesh/__init__.py +14 -0
  206. tensorbored/plugins/mesh/mesh_plugin.py +292 -0
  207. tensorbored/plugins/mesh/metadata.py +152 -0
  208. tensorbored/plugins/mesh/plugin_data_pb2.py +37 -0
  209. tensorbored/plugins/mesh/summary.py +251 -0
  210. tensorbored/plugins/mesh/summary_v2.py +214 -0
  211. tensorbored/plugins/metrics/__init__.py +0 -0
  212. tensorbored/plugins/metrics/metadata.py +17 -0
  213. tensorbored/plugins/metrics/metrics_plugin.py +623 -0
  214. tensorbored/plugins/pr_curve/__init__.py +0 -0
  215. tensorbored/plugins/pr_curve/metadata.py +75 -0
  216. tensorbored/plugins/pr_curve/plugin_data_pb2.py +34 -0
  217. tensorbored/plugins/pr_curve/pr_curves_plugin.py +241 -0
  218. tensorbored/plugins/pr_curve/summary.py +574 -0
  219. tensorbored/plugins/profile_redirect/__init__.py +0 -0
  220. tensorbored/plugins/profile_redirect/profile_redirect_plugin.py +49 -0
  221. tensorbored/plugins/projector/__init__.py +67 -0
  222. tensorbored/plugins/projector/metadata.py +26 -0
  223. tensorbored/plugins/projector/projector_config_pb2.py +54 -0
  224. tensorbored/plugins/projector/projector_plugin.py +795 -0
  225. tensorbored/plugins/projector/tf_projector_plugin/index.js +32 -0
  226. tensorbored/plugins/projector/tf_projector_plugin/projector_binary.html +524 -0
  227. tensorbored/plugins/projector/tf_projector_plugin/projector_binary.js +15536 -0
  228. tensorbored/plugins/scalar/__init__.py +0 -0
  229. tensorbored/plugins/scalar/metadata.py +60 -0
  230. tensorbored/plugins/scalar/plugin_data_pb2.py +34 -0
  231. tensorbored/plugins/scalar/scalars_plugin.py +181 -0
  232. tensorbored/plugins/scalar/summary.py +109 -0
  233. tensorbored/plugins/scalar/summary_v2.py +124 -0
  234. tensorbored/plugins/text/__init__.py +0 -0
  235. tensorbored/plugins/text/metadata.py +62 -0
  236. tensorbored/plugins/text/plugin_data_pb2.py +34 -0
  237. tensorbored/plugins/text/summary.py +114 -0
  238. tensorbored/plugins/text/summary_v2.py +124 -0
  239. tensorbored/plugins/text/text_plugin.py +288 -0
  240. tensorbored/plugins/wit_redirect/__init__.py +0 -0
  241. tensorbored/plugins/wit_redirect/wit_redirect_plugin.py +49 -0
  242. tensorbored/program.py +910 -0
  243. tensorbored/summary/__init__.py +35 -0
  244. tensorbored/summary/_output.py +124 -0
  245. tensorbored/summary/_tf/__init__.py +14 -0
  246. tensorbored/summary/_tf/summary/__init__.py +178 -0
  247. tensorbored/summary/_writer.py +105 -0
  248. tensorbored/summary/v1.py +51 -0
  249. tensorbored/summary/v2.py +25 -0
  250. tensorbored/summary/writer/__init__.py +13 -0
  251. tensorbored/summary/writer/event_file_writer.py +291 -0
  252. tensorbored/summary/writer/record_writer.py +50 -0
  253. tensorbored/util/__init__.py +0 -0
  254. tensorbored/util/encoder.py +116 -0
  255. tensorbored/util/grpc_util.py +311 -0
  256. tensorbored/util/img_mime_type_detector.py +40 -0
  257. tensorbored/util/io_util.py +20 -0
  258. tensorbored/util/lazy_tensor_creator.py +110 -0
  259. tensorbored/util/op_evaluator.py +104 -0
  260. tensorbored/util/platform_util.py +20 -0
  261. tensorbored/util/tb_logging.py +24 -0
  262. tensorbored/util/tensor_util.py +617 -0
  263. tensorbored/util/timing.py +122 -0
  264. tensorbored/version.py +21 -0
  265. tensorbored/webfiles.zip +0 -0
  266. tensorbored-2.21.0rc1769983804.dist-info/METADATA +49 -0
  267. tensorbored-2.21.0rc1769983804.dist-info/RECORD +271 -0
  268. tensorbored-2.21.0rc1769983804.dist-info/WHEEL +5 -0
  269. tensorbored-2.21.0rc1769983804.dist-info/entry_points.txt +6 -0
  270. tensorbored-2.21.0rc1769983804.dist-info/licenses/LICENSE +739 -0
  271. tensorbored-2.21.0rc1769983804.dist-info/top_level.txt +1 -0
@@ -0,0 +1,113 @@
1
+ # Copyright 2022 The TensorFlow Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Middleware for injecting client-side feature flags into the Context."""
16
+
17
+ import json
18
+ import urllib.parse
19
+
20
+ from tensorbored import context
21
+ from tensorbored import errors
22
+
23
+
24
+ class ClientFeatureFlagsMiddleware:
25
+ """Middleware for injecting client-side feature flags into the Context.
26
+
27
+ The client webapp is expected to include a json-serialized version of its
28
+ FeatureFlags in the `X-TensorBoard-Feature-Flags` header or the
29
+ `tensorBoardFeatureFlags` query parameter. This middleware extracts the
30
+ header or query parameter value and converts it into the client_feature_flags
31
+ property for the DataProvider's Context object, where client_feature_flags
32
+ is a Dict of string keys and arbitrary value types.
33
+
34
+ In the event that both the header and query parameter are specified, the
35
+ values from the header will take precedence.
36
+ """
37
+
38
+ def __init__(self, application):
39
+ """Initializes this middleware.
40
+
41
+ Args:
42
+ application: The WSGI application to wrap (see PEP 3333).
43
+ """
44
+ self._application = application
45
+
46
+ def __call__(self, environ, start_response):
47
+ header_feature_flags = self._parse_potential_header_param_flags(
48
+ environ.get("HTTP_X_TENSORBOARD_FEATURE_FLAGS")
49
+ )
50
+ query_string_feature_flags = self._parse_potential_query_param_flags(
51
+ environ.get("QUERY_STRING")
52
+ )
53
+
54
+ if not header_feature_flags and not query_string_feature_flags:
55
+ return self._application(environ, start_response)
56
+
57
+ # header flags take precedence
58
+ for flag, value in header_feature_flags.items():
59
+ query_string_feature_flags[flag] = value
60
+
61
+ ctx = context.from_environ(environ).replace(
62
+ client_feature_flags=query_string_feature_flags
63
+ )
64
+ context.set_in_environ(environ, ctx)
65
+
66
+ return self._application(environ, start_response)
67
+
68
+ def _parse_potential_header_param_flags(self, header_string):
69
+ if not header_string:
70
+ return {}
71
+
72
+ try:
73
+ header_feature_flags = json.loads(header_string)
74
+ except json.JSONDecodeError:
75
+ raise errors.InvalidArgumentError(
76
+ "X-TensorBoard-Feature-Flags cannot be JSON decoded."
77
+ )
78
+
79
+ if not isinstance(header_feature_flags, dict):
80
+ raise errors.InvalidArgumentError(
81
+ "X-TensorBoard-Feature-Flags cannot be decoded to a dict."
82
+ )
83
+
84
+ return header_feature_flags
85
+
86
+ def _parse_potential_query_param_flags(self, query_string):
87
+ if not query_string:
88
+ return {}
89
+
90
+ try:
91
+ query_string_json = urllib.parse.parse_qs(query_string)
92
+ except ValueError:
93
+ return {}
94
+
95
+ # parse_qs returns the dictionary values as lists for each name.
96
+ potential_feature_flags = query_string_json.get(
97
+ "tensorBoardFeatureFlags", []
98
+ )
99
+ if not potential_feature_flags:
100
+ return {}
101
+ try:
102
+ client_feature_flags = json.loads(potential_feature_flags[0])
103
+ except json.JSONDecodeError:
104
+ raise errors.InvalidArgumentError(
105
+ "tensorBoardFeatureFlags cannot be JSON decoded."
106
+ )
107
+
108
+ if not isinstance(client_feature_flags, dict):
109
+ raise errors.InvalidArgumentError(
110
+ "tensorBoardFeatureFlags cannot be decoded to a dict."
111
+ )
112
+
113
+ return client_feature_flags
@@ -0,0 +1,46 @@
1
+ # Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Redirect from an empty path to the virtual application root.
16
+
17
+ Sometimes, middleware transformations will make the path empty: for
18
+ example, navigating to "/foo" (no trailing slash) when the path prefix
19
+ is exactly "/foo". In such cases, relative links on the frontend would
20
+ break. Instead of handling this special case in each relevant
21
+ middleware, we install a top-level redirect handler from "" to "/".
22
+
23
+ This middleware respects `SCRIPT_NAME` as described by the WSGI spec. If
24
+ `SCRIPT_NAME` is set to "/foo", then an empty `PATH_INFO` corresponds to
25
+ the actual path "/foo", and so will be redirected to "/foo/".
26
+ """
27
+
28
+
29
+ class EmptyPathRedirectMiddleware:
30
+ """WSGI middleware to redirect from "" to "/"."""
31
+
32
+ def __init__(self, application):
33
+ """Initializes this middleware.
34
+
35
+ Args:
36
+ application: The WSGI application to wrap (see PEP 3333).
37
+ """
38
+ self._application = application
39
+
40
+ def __call__(self, environ, start_response):
41
+ path = environ.get("PATH_INFO", "")
42
+ if path:
43
+ return self._application(environ, start_response)
44
+ location = environ.get("SCRIPT_NAME", "") + "/"
45
+ start_response("301 Moved Permanently", [("Location", location)])
46
+ return []
File without changes
@@ -0,0 +1,276 @@
1
+ # Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Provides data ingestion logic backed by local event processing."""
16
+
17
+ import os
18
+ import re
19
+ import threading
20
+ import time
21
+
22
+
23
+ from tensorbored.backend.event_processing import data_provider
24
+ from tensorbored.backend.event_processing import plugin_event_multiplexer
25
+ from tensorbored.backend.event_processing import tag_types
26
+ from tensorbored.compat import tf
27
+ from tensorbored.data import ingester
28
+ from tensorbored.plugins.audio import metadata as audio_metadata
29
+ from tensorbored.plugins.histogram import metadata as histogram_metadata
30
+ from tensorbored.plugins.image import metadata as image_metadata
31
+ from tensorbored.plugins.pr_curve import metadata as pr_curve_metadata
32
+ from tensorbored.plugins.scalar import metadata as scalar_metadata
33
+ from tensorbored.util import tb_logging
34
+
35
+ DEFAULT_SIZE_GUIDANCE = {
36
+ tag_types.TENSORS: 10,
37
+ }
38
+
39
+ # TODO(@wchargin): Replace with something that works for third-party plugins.
40
+ DEFAULT_TENSOR_SIZE_GUIDANCE = {
41
+ scalar_metadata.PLUGIN_NAME: 1000,
42
+ image_metadata.PLUGIN_NAME: 10,
43
+ audio_metadata.PLUGIN_NAME: 10,
44
+ histogram_metadata.PLUGIN_NAME: 500,
45
+ pr_curve_metadata.PLUGIN_NAME: 100,
46
+ }
47
+
48
+ logger = tb_logging.get_logger()
49
+
50
+
51
+ class LocalDataIngester(ingester.DataIngester):
52
+ """Data ingestion implementation to use when running locally."""
53
+
54
+ def __init__(self, flags):
55
+ """Initializes a `LocalDataIngester` from `flags`.
56
+
57
+ Args:
58
+ flags: An argparse.Namespace containing TensorBoard CLI flags.
59
+
60
+ Returns:
61
+ The new `LocalDataIngester`.
62
+ """
63
+ tensor_size_guidance = dict(DEFAULT_TENSOR_SIZE_GUIDANCE)
64
+ tensor_size_guidance.update(flags.samples_per_plugin)
65
+ self._multiplexer = plugin_event_multiplexer.EventMultiplexer(
66
+ size_guidance=DEFAULT_SIZE_GUIDANCE,
67
+ tensor_size_guidance=tensor_size_guidance,
68
+ purge_orphaned_data=flags.purge_orphaned_data,
69
+ max_reload_threads=flags.max_reload_threads,
70
+ event_file_active_filter=_get_event_file_active_filter(flags),
71
+ detect_file_replacement=flags.detect_file_replacement,
72
+ )
73
+ self._data_provider = data_provider.MultiplexerDataProvider(
74
+ self._multiplexer, flags.logdir or flags.logdir_spec
75
+ )
76
+ self._reload_interval = flags.reload_interval
77
+ self._reload_task = flags.reload_task
78
+ if flags.logdir:
79
+ self._path_to_run = {os.path.expanduser(flags.logdir): None}
80
+ else:
81
+ self._path_to_run = _parse_event_files_spec(flags.logdir_spec)
82
+
83
+ # Conditionally import tensorflow_io.
84
+ if getattr(tf, "__version__", "stub") != "stub":
85
+ _check_filesystem_support(self._path_to_run.keys())
86
+
87
+ @property
88
+ def data_provider(self):
89
+ return self._data_provider
90
+
91
+ @property
92
+ def deprecated_multiplexer(self):
93
+ return self._multiplexer
94
+
95
+ def start(self):
96
+ """Starts ingesting data based on the ingester flag configuration."""
97
+
98
+ def _reload():
99
+ while True:
100
+ start = time.time()
101
+ logger.info("TensorBoard reload process beginning")
102
+ for path, name in self._path_to_run.items():
103
+ self._multiplexer.AddRunsFromDirectory(path, name)
104
+ logger.info(
105
+ "TensorBoard reload process: Reload the whole Multiplexer"
106
+ )
107
+ self._multiplexer.Reload()
108
+ duration = time.time() - start
109
+ logger.info(
110
+ "TensorBoard done reloading. Load took %0.3f secs", duration
111
+ )
112
+ if self._reload_interval == 0:
113
+ # Only load the multiplexer once. Do not continuously reload.
114
+ break
115
+ time.sleep(self._reload_interval)
116
+
117
+ if self._reload_task == "process":
118
+ logger.info("Launching reload in a child process")
119
+ import multiprocessing
120
+
121
+ process = multiprocessing.Process(target=_reload, name="Reloader")
122
+ # Best-effort cleanup; on exit, the main TB parent process will attempt to
123
+ # kill all its daemonic children.
124
+ process.daemon = True
125
+ process.start()
126
+ elif self._reload_task in ("thread", "auto"):
127
+ logger.info("Launching reload in a daemon thread")
128
+ thread = threading.Thread(target=_reload, name="Reloader")
129
+ # Make this a daemon thread, which won't block TB from exiting.
130
+ thread.daemon = True
131
+ thread.start()
132
+ elif self._reload_task == "blocking":
133
+ if self._reload_interval != 0:
134
+ raise ValueError(
135
+ "blocking reload only allowed with load_interval=0"
136
+ )
137
+ _reload()
138
+ else:
139
+ raise ValueError("unrecognized reload_task: %s" % self._reload_task)
140
+
141
+
142
+ def _get_event_file_active_filter(flags):
143
+ """Returns a predicate for whether an event file load timestamp is active.
144
+
145
+ Returns:
146
+ A predicate function accepting a single UNIX timestamp float argument, or
147
+ None if multi-file loading is not enabled.
148
+ """
149
+ if not flags.reload_multifile:
150
+ return None
151
+ inactive_secs = flags.reload_multifile_inactive_secs
152
+ if inactive_secs == 0:
153
+ return None
154
+ if inactive_secs < 0:
155
+ return lambda timestamp: True
156
+ return lambda timestamp: timestamp + inactive_secs >= time.time()
157
+
158
+
159
+ def _parse_event_files_spec(logdir_spec):
160
+ """Parses `logdir_spec` into a map from paths to run group names.
161
+
162
+ The `--logdir_spec` flag format is a comma-separated list of path
163
+ specifications. A path spec looks like 'group_name:/path/to/directory' or
164
+ '/path/to/directory'; in the latter case, the group is unnamed. Group names
165
+ cannot start with a forward slash: /foo:bar/baz will be interpreted as a spec
166
+ with no name and path '/foo:bar/baz'.
167
+
168
+ Globs are not supported.
169
+
170
+ Args:
171
+ logdir: A comma-separated list of run specifications.
172
+ Returns:
173
+ A dict mapping directory paths to names like {'/path/to/directory': 'name'}.
174
+ Groups without an explicit name are named after their path. If logdir is
175
+ None, returns an empty dict, which is helpful for testing things that don't
176
+ require any valid runs.
177
+ """
178
+ files = {}
179
+ if logdir_spec is None:
180
+ return files
181
+ # Make sure keeping consistent with ParseURI in core/lib/io/path.cc
182
+ uri_pattern = re.compile("[a-zA-Z][0-9a-zA-Z.]*://.*")
183
+ for specification in logdir_spec.split(","):
184
+ # Check if the spec contains group. A spec start with xyz:// is regarded as
185
+ # URI path spec instead of group spec. If the spec looks like /foo:bar/baz,
186
+ # then we assume it's a path with a colon. If the spec looks like
187
+ # [a-zA-z]:\foo then we assume its a Windows path and not a single letter
188
+ # group
189
+ if (
190
+ uri_pattern.match(specification) is None
191
+ and ":" in specification
192
+ and specification[0] != "/"
193
+ and not os.path.splitdrive(specification)[0]
194
+ ):
195
+ # We split at most once so run_name:/path:with/a/colon will work.
196
+ run_name, _, path = specification.partition(":")
197
+ else:
198
+ run_name = None
199
+ path = specification
200
+ if uri_pattern.match(path) is None:
201
+ path = os.path.realpath(os.path.expanduser(path))
202
+ files[path] = run_name
203
+ return files
204
+
205
+
206
+ def _get_filesystem_scheme(path):
207
+ """Extracts filesystem scheme from a given path.
208
+
209
+ The filesystem scheme is usually separated by `://` from the local filesystem
210
+ path if given. For example, the scheme of `file://tmp/tf` is `file`.
211
+
212
+ Args:
213
+ path: A strings representing an input log directory.
214
+ Returns:
215
+ Filesystem scheme, None if the path doesn't contain one.
216
+ """
217
+ if "://" not in path:
218
+ return None
219
+ return path.split("://")[0]
220
+
221
+
222
+ def _check_filesystem_support(paths):
223
+ """Examines the list of filesystems user requested.
224
+
225
+ If TF I/O schemes are requested, try to import tensorflow_io module.
226
+
227
+ Args:
228
+ paths: A list of strings representing input log directories.
229
+ """
230
+ get_registered_schemes = getattr(
231
+ tf.io.gfile, "get_registered_schemes", None
232
+ )
233
+ registered_schemes = (
234
+ None if get_registered_schemes is None else get_registered_schemes()
235
+ )
236
+
237
+ # Only need to check one path for each scheme.
238
+ scheme_to_path = {_get_filesystem_scheme(path): path for path in paths}
239
+ missing_scheme = None
240
+ for scheme, path in scheme_to_path.items():
241
+ if scheme is None:
242
+ continue
243
+ # Use `tf.io.gfile.exists.get_registered_schemes` if possible.
244
+ if registered_schemes is not None:
245
+ if scheme not in registered_schemes:
246
+ missing_scheme = scheme
247
+ break
248
+ else:
249
+ # Fall back to `tf.io.gfile.exists`.
250
+ try:
251
+ tf.io.gfile.exists(path)
252
+ except tf.errors.UnimplementedError:
253
+ missing_scheme = scheme
254
+ break
255
+ except tf.errors.OpError:
256
+ # Swallow other errors; we aren't concerned about them at this point.
257
+ pass
258
+
259
+ if missing_scheme:
260
+ try:
261
+ import tensorflow_io # noqa: F401
262
+ except ImportError as e:
263
+ supported_schemes_msg = (
264
+ " (supported schemes: {})".format(registered_schemes)
265
+ if registered_schemes
266
+ else ""
267
+ )
268
+ raise tf.errors.UnimplementedError(
269
+ None,
270
+ None,
271
+ (
272
+ "Error: Unsupported filename scheme '{}'{}. For additional"
273
+ + " filesystem support, consider installing TensorFlow I/O"
274
+ + " (https://www.tensorflow.org/io) via `pip install tensorflow-io`."
275
+ ).format(missing_scheme, supported_schemes_msg),
276
+ ) from e