test_component_parser_kfp.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. #
  2. # Copyright 2018-2022 Elyra Authors
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import json
  17. import os
  18. from pathlib import Path
  19. from subprocess import CompletedProcess
  20. from subprocess import run
  21. from conftest import KFP_COMPONENT_CACHE_INSTANCE
  22. from conftest import TEST_CATALOG_NAME
  23. import jupyter_core.paths
  24. import pytest
  25. import yaml
  26. from elyra.metadata.metadata import Metadata
  27. from elyra.pipeline.catalog_connector import CatalogEntry
  28. from elyra.pipeline.catalog_connector import EntryData
  29. from elyra.pipeline.catalog_connector import FilesystemComponentCatalogConnector
  30. from elyra.pipeline.catalog_connector import UrlComponentCatalogConnector
  31. from elyra.pipeline.component_catalog import ComponentCache
  32. from elyra.pipeline.component_metadata import ComponentCatalogMetadata
  33. from elyra.pipeline.kfp.component_parser_kfp import KfpComponentParser
  34. from elyra.pipeline.runtime_type import RuntimeProcessorType
  35. COMPONENT_CATALOG_DIRECTORY = os.path.join(jupyter_core.paths.ENV_JUPYTER_PATH[0], "components")
  36. RUNTIME_PROCESSOR = RuntimeProcessorType.KUBEFLOW_PIPELINES
  37. def _get_resource_path(filename):
  38. pipeline_dir = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
  39. resource_path = os.path.join(pipeline_dir, "resources", "components", filename)
  40. resource_path = os.path.normpath(resource_path)
  41. return resource_path
  42. @pytest.mark.parametrize("catalog_instance", [KFP_COMPONENT_CACHE_INSTANCE], indirect=True)
  43. def test_component_catalog_load(component_cache, catalog_instance):
  44. components = component_cache.get_all_components(RUNTIME_PROCESSOR)
  45. assert len(components) > 0
  46. @pytest.mark.parametrize("create_inprocess", [True, False])
  47. async def test_modify_component_catalogs(jp_environ, component_cache, metadata_manager_with_teardown, create_inprocess):
  48. # Get initial set of components
  49. initial_components = component_cache.get_all_components(RUNTIME_PROCESSOR)
  50. # Create new registry instance with a single URL-based component
  51. paths = [_get_resource_path("kfp_test_operator.yaml")]
  52. instance_metadata = {
  53. "description": "A test registry",
  54. "runtime_type": RUNTIME_PROCESSOR.name,
  55. "categories": ["New Components"],
  56. "paths": paths,
  57. }
  58. registry_instance = Metadata(
  59. schema_name="local-file-catalog",
  60. name=TEST_CATALOG_NAME,
  61. display_name="New Test Registry",
  62. metadata=instance_metadata,
  63. )
  64. if create_inprocess:
  65. metadata_manager_with_teardown.create(TEST_CATALOG_NAME, registry_instance)
  66. else:
  67. res: CompletedProcess = run(
  68. [
  69. "elyra-metadata",
  70. "install",
  71. "component-catalogs",
  72. f"--schema_name={registry_instance.schema_name}",
  73. f"--json={registry_instance.to_json()}",
  74. f"--name={TEST_CATALOG_NAME}",
  75. ]
  76. )
  77. assert res.returncode == 0
  78. # Wait for update to complete
  79. component_cache.wait_for_all_cache_tasks()
  80. # Get new set of components from all active registries, including added test registry
  81. components_after_create = component_cache.get_all_components(RUNTIME_PROCESSOR)
  82. assert len(components_after_create) == len(initial_components) + 1
  83. added_component_names = [component.name for component in components_after_create]
  84. assert "Test Operator" in added_component_names
  85. assert "Test Operator No Inputs" not in added_component_names
  86. # Modify the test registry to add a path to the catalog instance
  87. paths.append(_get_resource_path("kfp_test_operator_no_inputs.yaml"))
  88. metadata_manager_with_teardown.update(TEST_CATALOG_NAME, registry_instance)
  89. # Wait for update to complete
  90. component_cache.wait_for_all_cache_tasks()
  91. # Get set of components from all active registries, including modified test registry
  92. components_after_update = component_cache.get_all_components(RUNTIME_PROCESSOR)
  93. assert len(components_after_update) == len(initial_components) + 2
  94. modified_component_names = [component.name for component in components_after_update]
  95. assert "Test Operator" in modified_component_names
  96. assert "Test Operator No Inputs" in modified_component_names
  97. # Delete the test registry
  98. metadata_manager_with_teardown.remove(TEST_CATALOG_NAME)
  99. # Wait for update to complete
  100. component_cache.wait_for_all_cache_tasks()
  101. # Check that components remaining after delete are the same as before the new catalog was added
  102. components_after_remove = component_cache.get_all_components(RUNTIME_PROCESSOR)
  103. assert len(components_after_remove) == len(initial_components)
  104. @pytest.mark.parametrize("create_inprocess", [True, False])
  105. async def test_directory_based_component_catalog(
  106. component_cache, metadata_manager_with_teardown, create_inprocess, tmpdir
  107. ):
  108. # Verify that the component cache is empty to prevent other tests
  109. # from having an impact on this' tests result
  110. initial_components = component_cache.get_all_components(RUNTIME_PROCESSOR)
  111. assert len(initial_components) == 0, initial_components[0].name
  112. # Create and populate a temporary catalog directory
  113. catalog_dir = Path(tmpdir) / "catalog"
  114. catalog_dir.mkdir()
  115. # Copy a few YAML files from ../resources/components to
  116. # the catalog directory
  117. directory_entries = {"download_data.yaml": None, "kfp_test_operator_no_inputs.yaml": None}
  118. for file in directory_entries:
  119. with open(_get_resource_path(file), "r") as fh_in:
  120. # read file
  121. data = fh_in.read()
  122. # extract and store component name
  123. directory_entries[file] = yaml.safe_load(data)["name"]
  124. # write (unchanged) file to destination
  125. with open(catalog_dir / file, "w") as fh_out:
  126. fh_out.write(data)
  127. # make sure the file exists in the destination
  128. assert (catalog_dir / file).is_file()
  129. # Create new directory-based registry
  130. instance_metadata = {
  131. "description": "A test registry",
  132. "runtime_type": RUNTIME_PROCESSOR.name,
  133. "categories": ["New Components"],
  134. "paths": [str(catalog_dir)],
  135. }
  136. registry_instance = Metadata(
  137. schema_name="local-directory-catalog",
  138. name=TEST_CATALOG_NAME,
  139. display_name="New Test Registry",
  140. metadata=instance_metadata,
  141. )
  142. if create_inprocess:
  143. metadata_manager_with_teardown.create(TEST_CATALOG_NAME, registry_instance)
  144. else:
  145. res: CompletedProcess = run(
  146. [
  147. "elyra-metadata",
  148. "install",
  149. "component-catalogs",
  150. f"--schema_name={registry_instance.schema_name}",
  151. f"--json={registry_instance.to_json()}",
  152. f"--name={TEST_CATALOG_NAME}",
  153. ]
  154. )
  155. assert res.returncode == 0
  156. # Wait for update to complete
  157. component_cache.wait_for_all_cache_tasks()
  158. # Verify that the number of components in the cache equals the number of
  159. # components in the directory catalog
  160. components_after_create = component_cache.get_all_components(RUNTIME_PROCESSOR)
  161. assert len(components_after_create) == len(directory_entries), components_after_create
  162. # Verify the component names
  163. added_component_names = [component.name for component in components_after_create]
  164. for component in directory_entries:
  165. assert directory_entries[component] in added_component_names
  166. # Delete the test registry and wait for updates to complete
  167. metadata_manager_with_teardown.remove(TEST_CATALOG_NAME)
  168. component_cache.wait_for_all_cache_tasks()
  169. def test_parse_kfp_component_file():
  170. # Define the appropriate reader for a filesystem-type component definition
  171. kfp_supported_file_types = [".yaml"]
  172. reader = FilesystemComponentCatalogConnector(kfp_supported_file_types)
  173. # Read contents of given path
  174. path = _get_resource_path("kfp_test_operator.yaml")
  175. catalog_entry_data = {"path": path}
  176. # Construct a catalog instance
  177. catalog_type = "local-file-catalog"
  178. catalog_instance = ComponentCatalogMetadata(
  179. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  180. )
  181. # Build the catalog entry data structures required for parsing
  182. entry_data = reader.get_entry_data(catalog_entry_data, {})
  183. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["path"])
  184. # Parse the component entry
  185. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  186. component = parser.parse(catalog_entry)[0]
  187. properties_json = ComponentCache.to_canvas_properties(component)
  188. # Ensure description is rendered even with an unescaped character
  189. description = 'This component description contains an unescaped " character'
  190. assert properties_json["current_parameters"]["component_description"] == description
  191. # Ensure component parameters are prefixed (and system parameters are not) and all hold correct values
  192. assert properties_json["current_parameters"]["label"] == ""
  193. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  194. assert properties_json["current_parameters"]["component_source"] == component_source
  195. assert properties_json["current_parameters"]["elyra_test_string_no_default"] == {
  196. "StringControl": "",
  197. "activeControl": "StringControl",
  198. }
  199. assert properties_json["current_parameters"]["elyra_test_string_default_value"] == {
  200. "StringControl": "default",
  201. "activeControl": "StringControl",
  202. }
  203. assert properties_json["current_parameters"]["elyra_test_string_default_empty"] == {
  204. "StringControl": "",
  205. "activeControl": "StringControl",
  206. }
  207. assert properties_json["current_parameters"]["elyra_test_bool_default"] == {
  208. "BooleanControl": False,
  209. "activeControl": "BooleanControl",
  210. }
  211. assert properties_json["current_parameters"]["elyra_test_bool_false"] == {
  212. "BooleanControl": False,
  213. "activeControl": "BooleanControl",
  214. }
  215. assert properties_json["current_parameters"]["elyra_test_bool_true"] == {
  216. "BooleanControl": True,
  217. "activeControl": "BooleanControl",
  218. }
  219. assert properties_json["current_parameters"]["elyra_test_int_default"] == {
  220. "NumberControl": 0,
  221. "activeControl": "NumberControl",
  222. }
  223. assert properties_json["current_parameters"]["elyra_test_int_zero"] == {
  224. "NumberControl": 0,
  225. "activeControl": "NumberControl",
  226. }
  227. assert properties_json["current_parameters"]["elyra_test_int_non_zero"] == {
  228. "NumberControl": 1,
  229. "activeControl": "NumberControl",
  230. }
  231. assert properties_json["current_parameters"]["elyra_test_float_default"] == {
  232. "NumberControl": 0.0,
  233. "activeControl": "NumberControl",
  234. }
  235. assert properties_json["current_parameters"]["elyra_test_float_zero"] == {
  236. "NumberControl": 0.0,
  237. "activeControl": "NumberControl",
  238. }
  239. assert properties_json["current_parameters"]["elyra_test_float_non_zero"] == {
  240. "NumberControl": 1.0,
  241. "activeControl": "NumberControl",
  242. }
  243. assert properties_json["current_parameters"]["elyra_test_dict_default"] == {
  244. "StringControl": "{}",
  245. "activeControl": "StringControl",
  246. } # {}
  247. assert properties_json["current_parameters"]["elyra_test_list_default"] == {
  248. "StringControl": "[]",
  249. "activeControl": "StringControl",
  250. } # []
  251. assert properties_json["current_parameters"]["elyra_mounted_volumes"] == {
  252. "StringControl": "",
  253. "activeControl": "StringControl",
  254. }
  255. # Ensure that the 'required' attribute was set correctly. KFP components default to required
  256. # unless explicitly marked otherwise in component YAML.
  257. required_property = next(
  258. prop
  259. for prop in properties_json["uihints"]["parameter_info"]
  260. if prop.get("parameter_ref") == "elyra_test_required_property"
  261. )
  262. assert required_property["data"]["required"] is True
  263. optional_property = next(
  264. prop
  265. for prop in properties_json["uihints"]["parameter_info"]
  266. if prop.get("parameter_ref") == "elyra_test_optional_property"
  267. )
  268. assert optional_property["data"]["required"] is False
  269. default_required_property = next(
  270. prop
  271. for prop in properties_json["uihints"]["parameter_info"]
  272. if prop.get("parameter_ref") == "elyra_test_required_property_default"
  273. )
  274. assert default_required_property["data"]["required"] is True
  275. # Ensure that type information is inferred correctly
  276. unusual_dict_property = next(
  277. prop
  278. for prop in properties_json["uihints"]["parameter_info"]
  279. if prop.get("parameter_ref") == "elyra_test_unusual_type_dict"
  280. )
  281. assert unusual_dict_property["data"]["controls"]["StringControl"]["format"] == "dictionary"
  282. unusual_list_property = next(
  283. prop
  284. for prop in properties_json["uihints"]["parameter_info"]
  285. if prop.get("parameter_ref") == "elyra_test_unusual_type_list"
  286. )
  287. assert unusual_list_property["data"]["controls"]["StringControl"]["format"] == "list"
  288. unusual_string_property = next(
  289. prop
  290. for prop in properties_json["uihints"]["parameter_info"]
  291. if prop.get("parameter_ref") == "elyra_test_unusual_type_string"
  292. )
  293. assert unusual_string_property["data"]["controls"]["StringControl"]["format"] == "string"
  294. no_type_property = next(
  295. prop
  296. for prop in properties_json["uihints"]["parameter_info"]
  297. if prop.get("parameter_ref") == "elyra_test_unusual_type_notgiven"
  298. )
  299. assert no_type_property["data"]["controls"]["StringControl"]["format"] == "string"
  300. # Ensure descriptions are rendered properly with type hint in parentheses
  301. assert (
  302. unusual_dict_property["description"]["default"] == "The test command description "
  303. "(type: Dictionary of arrays)"
  304. )
  305. assert unusual_list_property["description"]["default"] == "The test command description (type: An array)"
  306. assert unusual_string_property["description"]["default"] == "The test command description (type: A string)"
  307. assert no_type_property["description"]["default"] == "The test command description (type: string)"
  308. def test_parse_kfp_component_url():
  309. # Define the appropriate reader for a URL-type component definition
  310. kfp_supported_file_types = [".yaml"]
  311. reader = UrlComponentCatalogConnector(kfp_supported_file_types)
  312. # Read contents of given path
  313. url = "https://raw.githubusercontent.com/kubeflow/pipelines/1.4.1/components/notebooks/Run_notebook_using_papermill/component.yaml" # noqa: E501
  314. catalog_entry_data = {"url": url}
  315. # Construct a catalog instance
  316. catalog_type = "url-catalog"
  317. catalog_instance = ComponentCatalogMetadata(
  318. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  319. )
  320. # Build the catalog entry data structures required for parsing
  321. entry_data = reader.get_entry_data(catalog_entry_data, {})
  322. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["url"])
  323. # Parse the component entry
  324. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  325. component = parser.parse(catalog_entry)[0]
  326. properties_json = ComponentCache.to_canvas_properties(component)
  327. # Ensure component parameters are prefixed (and system parameters are not) and all hold correct values
  328. assert properties_json["current_parameters"]["label"] == ""
  329. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  330. assert properties_json["current_parameters"]["component_source"] == component_source
  331. assert properties_json["current_parameters"]["elyra_notebook"] == "None" # Default value for type `inputpath`
  332. assert properties_json["current_parameters"]["elyra_parameters"] == {
  333. "StringControl": "{}",
  334. "activeControl": "StringControl",
  335. }
  336. assert properties_json["current_parameters"]["elyra_packages_to_install"] == {
  337. "StringControl": "[]",
  338. "activeControl": "StringControl",
  339. }
  340. assert properties_json["current_parameters"]["elyra_input_data"] == {
  341. "StringControl": "",
  342. "activeControl": "StringControl",
  343. }
  344. def test_parse_kfp_component_file_no_inputs():
  345. # Define the appropriate reader for a filesystem-type component definition
  346. kfp_supported_file_types = [".yaml"]
  347. reader = FilesystemComponentCatalogConnector(kfp_supported_file_types)
  348. # Read contents of given path
  349. path = _get_resource_path("kfp_test_operator_no_inputs.yaml")
  350. catalog_entry_data = {"path": path}
  351. # Construct a catalog instance
  352. catalog_type = "local-file-catalog"
  353. catalog_instance = ComponentCatalogMetadata(
  354. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  355. )
  356. # Build the catalog entry data structures required for parsing
  357. entry_data = reader.get_entry_data(catalog_entry_data, {})
  358. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["path"])
  359. # Parse the component entry
  360. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  361. component = parser.parse(catalog_entry)[0]
  362. properties_json = ComponentCache.to_canvas_properties(component)
  363. # Properties JSON should only include the five parameters common to every
  364. # component ('label', 'component_source', 'mounted_volumes', 'kubernetes_pod_annotations',
  365. # 'kubernetes_tolerations', and 'elyra_disallow_cached_output'), the component description if
  366. # it exists (which it does for this component), and the output parameter for this component
  367. num_common_params = 8
  368. assert len(properties_json["current_parameters"].keys()) == num_common_params, properties_json["current_parameters"]
  369. assert len(properties_json["parameters"]) == num_common_params
  370. assert len(properties_json["uihints"]["parameter_info"]) == num_common_params
  371. # Total number of groups includes one for each parameter,
  372. # plus 1 for the output group header,
  373. # plus 1 for the component_source header,
  374. # plus 1 for the 'other properties' header (that includes, e.g., mounted_volumes)
  375. num_groups = num_common_params + 3
  376. assert len(properties_json["uihints"]["group_info"][0]["group_info"]) == num_groups
  377. # Ensure that template still renders the two common parameters correctly
  378. assert properties_json["current_parameters"]["label"] == ""
  379. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  380. assert properties_json["current_parameters"]["component_source"] == component_source
  381. async def test_parse_components_not_a_file():
  382. # Define the appropriate reader for a filesystem-type component definition
  383. kfp_supported_file_types = [".yaml"]
  384. reader = FilesystemComponentCatalogConnector(kfp_supported_file_types)
  385. # Get path to an invalid component definition file and read contents
  386. path = _get_resource_path("kfp_test_operator_not_a_file.yaml")
  387. entry_data = reader.get_entry_data({"path": path}, {})
  388. assert entry_data is None
  389. async def test_parse_components_invalid_yaml(caplog):
  390. # Get resource path and read definition (by-pass catalog reader functionality)
  391. path = _get_resource_path("kfp_test_invalid_component.yaml")
  392. with open(path, "r") as f:
  393. definition = f.read()
  394. # Manually construct catalog_entry_data object and catalog instance
  395. catalog_entry_data = {"path": path}
  396. catalog_type = "local-file-catalog"
  397. catalog_instance = ComponentCatalogMetadata(
  398. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  399. )
  400. # Build the catalog entry data structures required for parsing
  401. entry_data = EntryData(definition=definition)
  402. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["path"])
  403. # Parse the component entry
  404. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  405. component = parser.parse(catalog_entry)
  406. # Failed YAML schema validation returns None
  407. assert component is None
  408. # Assert validation error is captured appropriately in log
  409. assert "Invalid format of YAML definition for component" in caplog.text
  410. assert "Failed validating 'type'" in caplog.text
  411. assert "On instance['inputs'][0]['name']:\n 2" in caplog.text
  412. caplog.clear()
  413. # Modify file to get expected error in YAML safe_load
  414. new_definition = "key with no mapping\n" + definition
  415. catalog_entry.entry_data.definition = new_definition
  416. # Re-parse with new definition content
  417. component = parser.parse(catalog_entry)
  418. # Failed YAML safe_load returns None
  419. assert component is None
  420. # Assert load error is captured appropriately in log
  421. assert "Could not load YAML definition for component" in caplog.text
  422. assert "mapping values are not allowed here" in caplog.text
  423. async def test_parse_components_additional_metatypes():
  424. # Define the appropriate reader for a URL-type component definition
  425. kfp_supported_file_types = [".yaml"]
  426. reader = UrlComponentCatalogConnector(kfp_supported_file_types)
  427. # Read contents of given path
  428. url = "https://raw.githubusercontent.com/kubeflow/pipelines/1.4.1/components/keras/Train_classifier/from_CSV/component.yaml" # noqa: E501
  429. catalog_entry_data = {"url": url}
  430. # Construct a catalog instance
  431. catalog_type = "url-catalog"
  432. catalog_instance = ComponentCatalogMetadata(
  433. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  434. )
  435. # Build the catalog entry data structures required for parsing
  436. entry_data = reader.get_entry_data(catalog_entry_data, {})
  437. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["url"])
  438. # Parse the component entry
  439. parser = KfpComponentParser()
  440. component = parser.parse(catalog_entry)[0]
  441. properties_json = ComponentCache.to_canvas_properties(component)
  442. # Ensure component parameters are prefixed (and system parameters are not) and all hold correct values
  443. assert properties_json["current_parameters"]["label"] == ""
  444. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  445. assert properties_json["current_parameters"]["component_source"] == component_source
  446. assert properties_json["current_parameters"]["elyra_training_features"] == "None" # inputPath
  447. assert properties_json["current_parameters"]["elyra_training_labels"] == "None" # inputPath
  448. assert properties_json["current_parameters"]["elyra_network_json"] == "None" # inputPath
  449. assert properties_json["current_parameters"]["elyra_loss_name"] == {
  450. "StringControl": "categorical_crossentropy",
  451. "activeControl": "StringControl",
  452. }
  453. assert properties_json["current_parameters"]["elyra_num_classes"] == {
  454. "NumberControl": 0,
  455. "activeControl": "NumberControl",
  456. }
  457. assert properties_json["current_parameters"]["elyra_optimizer"] == {
  458. "StringControl": "rmsprop",
  459. "activeControl": "StringControl",
  460. }
  461. assert properties_json["current_parameters"]["elyra_optimizer_config"] == {
  462. "StringControl": "",
  463. "activeControl": "StringControl",
  464. }
  465. assert properties_json["current_parameters"]["elyra_learning_rate"] == {
  466. "NumberControl": 0.01,
  467. "activeControl": "NumberControl",
  468. }
  469. assert properties_json["current_parameters"]["elyra_num_epochs"] == {
  470. "NumberControl": 100,
  471. "activeControl": "NumberControl",
  472. }
  473. assert properties_json["current_parameters"]["elyra_batch_size"] == {
  474. "NumberControl": 32,
  475. "activeControl": "NumberControl",
  476. }
  477. assert properties_json["current_parameters"]["elyra_metrics"] == {
  478. "StringControl": "['accuracy']",
  479. "activeControl": "StringControl",
  480. }
  481. assert properties_json["current_parameters"]["elyra_random_seed"] == {
  482. "NumberControl": 0,
  483. "activeControl": "NumberControl",
  484. }