test_component_parser_kfp.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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. root = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
  39. resource_path = os.path.join(root, "..", "..", "..", "tests/pipeline", "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. # Ensure that the 'required' attribute was set correctly. KFP components default to required
  252. # unless explicitly marked otherwise in component YAML.
  253. required_property = next(
  254. prop
  255. for prop in properties_json["uihints"]["parameter_info"]
  256. if prop.get("parameter_ref") == "elyra_test_required_property"
  257. )
  258. assert required_property["data"]["required"] is True
  259. optional_property = next(
  260. prop
  261. for prop in properties_json["uihints"]["parameter_info"]
  262. if prop.get("parameter_ref") == "elyra_test_optional_property"
  263. )
  264. assert optional_property["data"]["required"] is False
  265. default_required_property = next(
  266. prop
  267. for prop in properties_json["uihints"]["parameter_info"]
  268. if prop.get("parameter_ref") == "elyra_test_required_property_default"
  269. )
  270. assert default_required_property["data"]["required"] is True
  271. # Ensure that type information is inferred correctly
  272. unusual_dict_property = next(
  273. prop
  274. for prop in properties_json["uihints"]["parameter_info"]
  275. if prop.get("parameter_ref") == "elyra_test_unusual_type_dict"
  276. )
  277. assert unusual_dict_property["data"]["controls"]["StringControl"]["format"] == "dictionary"
  278. unusual_list_property = next(
  279. prop
  280. for prop in properties_json["uihints"]["parameter_info"]
  281. if prop.get("parameter_ref") == "elyra_test_unusual_type_list"
  282. )
  283. assert unusual_list_property["data"]["controls"]["StringControl"]["format"] == "list"
  284. unusual_string_property = next(
  285. prop
  286. for prop in properties_json["uihints"]["parameter_info"]
  287. if prop.get("parameter_ref") == "elyra_test_unusual_type_string"
  288. )
  289. assert unusual_string_property["data"]["controls"]["StringControl"]["format"] == "string"
  290. file_property = next(
  291. prop
  292. for prop in properties_json["uihints"]["parameter_info"]
  293. if prop.get("parameter_ref") == "elyra_test_unusual_type_file"
  294. )
  295. assert file_property["data"]["format"] == "inputpath"
  296. no_type_property = next(
  297. prop
  298. for prop in properties_json["uihints"]["parameter_info"]
  299. if prop.get("parameter_ref") == "elyra_test_unusual_type_notgiven"
  300. )
  301. assert no_type_property["data"]["controls"]["StringControl"]["format"] == "string"
  302. # Ensure descriptions are rendered properly with type hint in parentheses
  303. assert (
  304. unusual_dict_property["description"]["default"] == "The test command description "
  305. "(type: Dictionary of arrays)"
  306. )
  307. assert unusual_list_property["description"]["default"] == "The test command description (type: An array)"
  308. assert unusual_string_property["description"]["default"] == "The test command description (type: A string)"
  309. assert (
  310. file_property["description"]["default"] == "The test command description"
  311. ) # No data type info is included in parentheses for inputPath variables
  312. assert no_type_property["description"]["default"] == "The test command description (type: string)"
  313. def test_parse_kfp_component_url():
  314. # Define the appropriate reader for a URL-type component definition
  315. kfp_supported_file_types = [".yaml"]
  316. reader = UrlComponentCatalogConnector(kfp_supported_file_types)
  317. # Read contents of given path
  318. url = "https://raw.githubusercontent.com/kubeflow/pipelines/1.4.1/components/notebooks/Run_notebook_using_papermill/component.yaml" # noqa: E501
  319. catalog_entry_data = {"url": url}
  320. # Construct a catalog instance
  321. catalog_type = "url-catalog"
  322. catalog_instance = ComponentCatalogMetadata(
  323. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  324. )
  325. # Build the catalog entry data structures required for parsing
  326. entry_data = reader.get_entry_data(catalog_entry_data, {})
  327. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["url"])
  328. # Parse the component entry
  329. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  330. component = parser.parse(catalog_entry)[0]
  331. properties_json = ComponentCache.to_canvas_properties(component)
  332. # Ensure component parameters are prefixed (and system parameters are not) and all hold correct values
  333. assert properties_json["current_parameters"]["label"] == ""
  334. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  335. assert properties_json["current_parameters"]["component_source"] == component_source
  336. assert properties_json["current_parameters"]["elyra_notebook"] == "None" # Default value for type `inputpath`
  337. assert properties_json["current_parameters"]["elyra_parameters"] == {
  338. "StringControl": "{}",
  339. "activeControl": "StringControl",
  340. }
  341. assert properties_json["current_parameters"]["elyra_packages_to_install"] == {
  342. "StringControl": "[]",
  343. "activeControl": "StringControl",
  344. }
  345. assert properties_json["current_parameters"]["elyra_input_data"] == {
  346. "StringControl": "",
  347. "activeControl": "StringControl",
  348. }
  349. def test_parse_kfp_component_file_no_inputs():
  350. # Define the appropriate reader for a filesystem-type component definition
  351. kfp_supported_file_types = [".yaml"]
  352. reader = FilesystemComponentCatalogConnector(kfp_supported_file_types)
  353. # Read contents of given path
  354. path = _get_resource_path("kfp_test_operator_no_inputs.yaml")
  355. catalog_entry_data = {"path": path}
  356. # Construct a catalog instance
  357. catalog_type = "local-file-catalog"
  358. catalog_instance = ComponentCatalogMetadata(
  359. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  360. )
  361. # Build the catalog entry data structures required for parsing
  362. entry_data = reader.get_entry_data(catalog_entry_data, {})
  363. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["path"])
  364. # Parse the component entry
  365. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  366. component = parser.parse(catalog_entry)[0]
  367. properties_json = ComponentCache.to_canvas_properties(component)
  368. # Properties JSON should only include the two parameters common to every
  369. # component:'label' and 'component_source', the component description if
  370. # exists (which it does for this component), and the output parameter for
  371. # this component
  372. num_common_params = 4
  373. assert len(properties_json["current_parameters"].keys()) == num_common_params
  374. assert len(properties_json["parameters"]) == num_common_params
  375. assert len(properties_json["uihints"]["parameter_info"]) == num_common_params
  376. # Total number of groups includes one for each parameter,
  377. # plus one for the output group header,
  378. # plus 1 for the component_source header
  379. num_groups = num_common_params + 2
  380. assert len(properties_json["uihints"]["group_info"][0]["group_info"]) == num_groups
  381. # Ensure that template still renders the two common parameters correctly
  382. assert properties_json["current_parameters"]["label"] == ""
  383. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  384. assert properties_json["current_parameters"]["component_source"] == component_source
  385. async def test_parse_components_not_a_file():
  386. # Define the appropriate reader for a filesystem-type component definition
  387. kfp_supported_file_types = [".yaml"]
  388. reader = FilesystemComponentCatalogConnector(kfp_supported_file_types)
  389. # Get path to an invalid component definition file and read contents
  390. path = _get_resource_path("kfp_test_operator_not_a_file.yaml")
  391. entry_data = reader.get_entry_data({"path": path}, {})
  392. assert entry_data is None
  393. async def test_parse_components_invalid_yaml(caplog):
  394. # Get resource path and read definition (by-pass catalog reader functionality)
  395. path = _get_resource_path("kfp_test_invalid_component.yaml")
  396. with open(path, "r") as f:
  397. definition = f.read()
  398. # Manually construct catalog_entry_data object and catalog instance
  399. catalog_entry_data = {"path": path}
  400. catalog_type = "local-file-catalog"
  401. catalog_instance = ComponentCatalogMetadata(
  402. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  403. )
  404. # Build the catalog entry data structures required for parsing
  405. entry_data = EntryData(definition=definition)
  406. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["path"])
  407. # Parse the component entry
  408. parser = KfpComponentParser.create_instance(platform=RUNTIME_PROCESSOR)
  409. component = parser.parse(catalog_entry)
  410. # Failed YAML schema validation returns None
  411. assert component is None
  412. # Assert validation error is captured appropriately in log
  413. assert "Invalid format of YAML definition for component" in caplog.text
  414. assert "Failed validating 'type'" in caplog.text
  415. assert "On instance['inputs'][0]['name']:\n 2" in caplog.text
  416. caplog.clear()
  417. # Modify file to get expected error in YAML safe_load
  418. new_definition = "key with no mapping\n" + definition
  419. catalog_entry.entry_data.definition = new_definition
  420. # Re-parse with new definition content
  421. component = parser.parse(catalog_entry)
  422. # Failed YAML safe_load returns None
  423. assert component is None
  424. # Assert load error is captured appropriately in log
  425. assert "Could not load YAML definition for component" in caplog.text
  426. assert "mapping values are not allowed here" in caplog.text
  427. async def test_parse_components_additional_metatypes():
  428. # Define the appropriate reader for a URL-type component definition
  429. kfp_supported_file_types = [".yaml"]
  430. reader = UrlComponentCatalogConnector(kfp_supported_file_types)
  431. # Read contents of given path
  432. url = "https://raw.githubusercontent.com/kubeflow/pipelines/1.4.1/components/keras/Train_classifier/from_CSV/component.yaml" # noqa: E501
  433. catalog_entry_data = {"url": url}
  434. # Construct a catalog instance
  435. catalog_type = "url-catalog"
  436. catalog_instance = ComponentCatalogMetadata(
  437. schema_name=catalog_type, metadata={"categories": ["Test"], "runtime_type": RUNTIME_PROCESSOR.name}
  438. )
  439. # Build the catalog entry data structures required for parsing
  440. entry_data = reader.get_entry_data(catalog_entry_data, {})
  441. catalog_entry = CatalogEntry(entry_data, catalog_entry_data, catalog_instance, ["url"])
  442. # Parse the component entry
  443. parser = KfpComponentParser()
  444. component = parser.parse(catalog_entry)[0]
  445. properties_json = ComponentCache.to_canvas_properties(component)
  446. # Ensure component parameters are prefixed (and system parameters are not) and all hold correct values
  447. assert properties_json["current_parameters"]["label"] == ""
  448. component_source = json.dumps({"catalog_type": catalog_type, "component_ref": catalog_entry.entry_reference})
  449. assert properties_json["current_parameters"]["component_source"] == component_source
  450. assert properties_json["current_parameters"]["elyra_training_features"] == "None" # inputPath
  451. assert properties_json["current_parameters"]["elyra_training_labels"] == "None" # inputPath
  452. assert properties_json["current_parameters"]["elyra_network_json"] == "None" # inputPath
  453. assert properties_json["current_parameters"]["elyra_loss_name"] == {
  454. "StringControl": "categorical_crossentropy",
  455. "activeControl": "StringControl",
  456. }
  457. assert properties_json["current_parameters"]["elyra_num_classes"] == {
  458. "NumberControl": 0,
  459. "activeControl": "NumberControl",
  460. }
  461. assert properties_json["current_parameters"]["elyra_optimizer"] == {
  462. "StringControl": "rmsprop",
  463. "activeControl": "StringControl",
  464. }
  465. assert properties_json["current_parameters"]["elyra_optimizer_config"] == {
  466. "StringControl": "",
  467. "activeControl": "StringControl",
  468. }
  469. assert properties_json["current_parameters"]["elyra_learning_rate"] == {
  470. "NumberControl": 0.01,
  471. "activeControl": "NumberControl",
  472. }
  473. assert properties_json["current_parameters"]["elyra_num_epochs"] == {
  474. "NumberControl": 100,
  475. "activeControl": "NumberControl",
  476. }
  477. assert properties_json["current_parameters"]["elyra_batch_size"] == {
  478. "NumberControl": 32,
  479. "activeControl": "NumberControl",
  480. }
  481. assert properties_json["current_parameters"]["elyra_metrics"] == {
  482. "StringControl": "['accuracy']",
  483. "activeControl": "StringControl",
  484. }
  485. assert properties_json["current_parameters"]["elyra_random_seed"] == {
  486. "NumberControl": 0,
  487. "activeControl": "NumberControl",
  488. }