diff --git a/README.rst b/README.rst index a90809a..7e17aea 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ Requirements ============ **niflexlogger-automation** has the following requirements: -* FlexLogger 2022 Q2+ +* FlexLogger 2023 Q2+ * CPython 3.6 - 3.10. If you do not have Python installed on your computer, go to python.org/downloads to download and install it. .. _installation_section: diff --git a/examples/Basic/get_log_file_description.py b/examples/Basic/get_log_file_description.py new file mode 100644 index 0000000..cd2bb38 --- /dev/null +++ b/examples/Basic/get_log_file_description.py @@ -0,0 +1,26 @@ +import os +import sys + +from flexlogger.automation import Application + + +def main(project_path): + """Launch FlexLogger, open a project, and get the log file description.""" + with Application.launch() as app: + project = app.open_project(path=project_path) + logging_specification = project.open_logging_specification_document() + log_file_description = logging_specification.get_log_file_description() + print("Log file description: " + log_file_description) + print("Press Enter to close the project...") + input() + project.close() + return 0 + + +if __name__ == "__main__": + argv = sys.argv + if len(argv) < 2: + print("Usage: %s " % os.path.basename(__file__)) + sys.exit() + project_path_arg = argv[1] + sys.exit(main(project_path_arg)) diff --git a/examples/Basic/get_test_properties.py b/examples/Basic/get_test_properties.py new file mode 100644 index 0000000..b9eb1d4 --- /dev/null +++ b/examples/Basic/get_test_properties.py @@ -0,0 +1,28 @@ +import os +import sys + +from flexlogger.automation import Application + + +def main(project_path): + """Launch FlexLogger, open a project, and get all test properties.""" + with Application.launch() as app: + project = app.open_project(path=project_path) + logging_specification = project.open_logging_specification_document() + test_properties = logging_specification.get_test_properties() + for test_property in test_properties: + prompt = "(prompt on start)" if test_property.prompt_on_start else "" + print(f'{test_property.name}: {test_property.value} {prompt}') + print("Press Enter to close the project...") + input() + project.close() + return 0 + + +if __name__ == "__main__": + argv = sys.argv + if len(argv) < 2: + print("Usage: %s " % os.path.basename(__file__)) + sys.exit() + project_path_arg = argv[1] + sys.exit(main(project_path_arg)) diff --git a/examples/Basic/set_data_rate.py b/examples/Basic/set_data_rate.py index 8a1e265..6454184 100644 --- a/examples/Basic/set_data_rate.py +++ b/examples/Basic/set_data_rate.py @@ -13,7 +13,7 @@ def main(project_path): - """Launch FlexLogger, open a project, and sets the data rate values.""" + """Launch FlexLogger, open a project, and set the data rate values.""" with Application.launch() as app: project = app.open_project(path=project_path) channel_specification = project.open_channel_specification_document() @@ -29,7 +29,6 @@ def main(project_path): print("Data rate set. Press Enter to save and close the project...") input() - project.save() project.close() return 0 diff --git a/examples/Basic/set_log_file_description.py b/examples/Basic/set_log_file_description.py new file mode 100644 index 0000000..50e2942 --- /dev/null +++ b/examples/Basic/set_log_file_description.py @@ -0,0 +1,26 @@ +import os +import sys + +from flexlogger.automation import Application + + +def main(project_path): + """Launch FlexLogger, open a project, and set the log file description.""" + with Application.launch() as app: + project = app.open_project(path=project_path) + log_file_description = input("Enter the log file description: ") + logging_specification = project.open_logging_specification_document() + logging_specification.set_log_file_description(log_file_description) + print("Log file description set. Press Enter to close the project...") + input() + project.close() + return 0 + + +if __name__ == "__main__": + argv = sys.argv + if len(argv) < 2: + print("Usage: %s " % os.path.basename(__file__)) + sys.exit() + project_path_arg = argv[1] + sys.exit(main(project_path_arg)) diff --git a/examples/Basic/set_test_properties.py b/examples/Basic/set_test_properties.py new file mode 100644 index 0000000..9d33f6b --- /dev/null +++ b/examples/Basic/set_test_properties.py @@ -0,0 +1,36 @@ +import os +import sys + +from flexlogger.automation import Application +from flexlogger.automation import TestProperty + + +def main(project_path): + """Launch FlexLogger, open a project, and set test properties.""" + with Application.launch() as app: + project = app.open_project(path=project_path) + logging_specification = project.open_logging_specification_document() + + test_properties = [] + while True: + name = input("Enter the name of the test property to set the value of (empty line to exit): ") + if name == "": + break + value = input("Enter the test property value: ") + prompt_on_start = input("Enter if you want to prompt on start (y/n): ") == "y" + test_properties.append(TestProperty(name, value, prompt_on_start)) + + logging_specification.set_test_properties(test_properties) + print("Press Enter to close the project...") + input() + project.close() + return 0 + + +if __name__ == "__main__": + argv = sys.argv + if len(argv) < 2: + print("Usage: %s " % os.path.basename(__file__)) + sys.exit() + project_path_arg = argv[1] + sys.exit(main(project_path_arg)) diff --git a/protobuf/ConfigurationBasedSoftware/FlexLogger/Automation/FlexLogger.Automation.Protocols/LoggingSpecificationDocument.proto b/protobuf/ConfigurationBasedSoftware/FlexLogger/Automation/FlexLogger.Automation.Protocols/LoggingSpecificationDocument.proto index e184175..8422b08 100644 --- a/protobuf/ConfigurationBasedSoftware/FlexLogger/Automation/FlexLogger.Automation.Protocols/LoggingSpecificationDocument.proto +++ b/protobuf/ConfigurationBasedSoftware/FlexLogger/Automation/FlexLogger.Automation.Protocols/LoggingSpecificationDocument.proto @@ -3,6 +3,7 @@ package national_instruments.flex_logger.automation.protocols; import "DiagramSdk/Automation/DiagramSdk.Automation.Protocols/Identifiers.proto"; +import "google/protobuf/empty.proto"; // Service interface for a server side logging specification document. service LoggingSpecificationDocument { @@ -14,8 +15,14 @@ service LoggingSpecificationDocument { rpc GetLogFileName(GetLogFileNameRequest) returns (GetLogFileNameResponse) {} // RPC call to set the log file name rpc SetLogFileName(SetLogFileNameRequest) returns (SetLogFileNameResponse) {} + // RPC call to get the description + rpc GetLogFileDescription(GetLogFileDescriptionRequest) returns (GetLogFileDescriptionResponse) {} + // RPC call to set the description + rpc SetLogFileDescription(SetLogFileDescriptionRequest) returns (google.protobuf.Empty) {} // RPC call to get all test properties rpc GetTestProperties(GetTestPropertiesRequest) returns (GetTestPropertiesResponse) {} + // RPC call to set all test properties + rpc SetTestProperties(SetTestPropertiesRequest) returns (google.protobuf.Empty) {} // RPC call to get a specific test property rpc GetTestProperty(GetTestPropertyRequest) returns (GetTestPropertyResponse) {} // RPC call to set a specific test property @@ -68,7 +75,7 @@ message GetLogFileNameResponse { message SetLogFileNameRequest { // The id for the logging specification document national_instruments.diagram_sdk.automation.protocols.ElementIdentifier document_identifier = 1; - // The log file base path + // The log file name string log_file_name = 2; } @@ -76,6 +83,26 @@ message SetLogFileNameRequest { message SetLogFileNameResponse { } +// Request object for getting the log file description +message GetLogFileDescriptionRequest { + // The id for the logging specification document + national_instruments.diagram_sdk.automation.protocols.ElementIdentifier document_identifier = 1; +} + +// Response object for a get log file description request +message GetLogFileDescriptionResponse { + // The log file description + string log_file_description = 1; +} + +// Request object for setting the log file description +message SetLogFileDescriptionRequest { + // The id for the logging specification document + national_instruments.diagram_sdk.automation.protocols.ElementIdentifier document_identifier = 1; + // The log file description + string log_file_description = 2; +} + // Message that defines an individual test property message TestProperty { string property_name = 1; @@ -95,6 +122,14 @@ message GetTestPropertiesResponse { repeated TestProperty test_properties = 1; } +// Request object for setting all test properties +message SetTestPropertiesRequest { + // The id for the logging specification document + national_instruments.diagram_sdk.automation.protocols.ElementIdentifier document_identifier = 1; + // The test properties for the logging specification document. Can be empty. + repeated TestProperty test_properties = 2; +} + // Request object for getting a specific test property message GetTestPropertyRequest { // The id for the logging specification document diff --git a/setup.py b/setup.py index 830ecfb..cee77d4 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ def _get_version(name: str) -> str: script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.join(script_dir, name) if not os.path.exists(os.path.join(script_dir, "VERSION")): - version = "0.1.4" + version = "0.1.5" else: with open(os.path.join(script_dir, "VERSION"), "r") as version_file: version = version_file.read().rstrip() diff --git a/src/flexlogger/automation/_logging_specification_document.py b/src/flexlogger/automation/_logging_specification_document.py index 39fac02..3010c52 100644 --- a/src/flexlogger/automation/_logging_specification_document.py +++ b/src/flexlogger/automation/_logging_specification_document.py @@ -157,6 +157,47 @@ def set_log_file_name(self, log_file_name: str) -> None: self._raise_if_application_closed() raise FlexLoggerError("Failed to set log file name") from error + def get_log_file_description(self) -> str: + """Get the log file description. + + Returns: + The description of the log file. + + Raises: + FlexLoggerError: if getting the log file description fails. + """ + stub = LoggingSpecificationDocument_pb2_grpc.LoggingSpecificationDocumentStub(self._channel) + try: + response = stub.GetLogFileDescription( + LoggingSpecificationDocument_pb2.GetLogFileDescriptionRequest( + document_identifier=self._identifier + ) + ) + return response.log_file_description + except (RpcError, ValueError) as error: + self._raise_if_application_closed() + raise FlexLoggerError("Failed to get log file description") from error + + def set_log_file_description(self, log_file_description: str) -> None: + """Set the log file description. + + Args: + log_file_description: The log file description. + + Raises: + FlexLoggerError: if setting the log file description fails. + """ + stub = LoggingSpecificationDocument_pb2_grpc.LoggingSpecificationDocumentStub(self._channel) + try: + stub.SetLogFileDescription( + LoggingSpecificationDocument_pb2.SetLogFileDescriptionRequest( + document_identifier=self._identifier, log_file_description=log_file_description + ) + ) + except (RpcError, ValueError) as error: + self._raise_if_application_closed() + raise FlexLoggerError("Failed to set log file description") from error + def _convert_to_test_property( self, test_property: LoggingSpecificationDocument_pb2.TestProperty ) -> TestProperty: @@ -166,6 +207,15 @@ def _convert_to_test_property( test_property.prompt_on_start, ) + def _convert_from_test_property( + self, test_property: TestProperty + ) -> LoggingSpecificationDocument_pb2.TestProperty: + return LoggingSpecificationDocument_pb2.TestProperty( + property_name=test_property.name, + property_value=test_property.value, + prompt_on_start=test_property.prompt_on_start, + ) + def get_test_properties(self) -> List[TestProperty]: """Get all test properties. @@ -187,6 +237,29 @@ def get_test_properties(self) -> List[TestProperty]: self._raise_if_application_closed() raise FlexLoggerError("Failed to get test properties") from error + def set_test_properties(self, test_properties: List[TestProperty]) -> None: + """Set test properties. + + Args: + test_properties: A list of test properties to add or modify on this document. + + Raises: + FlexLoggerError: if setting the test properties fails. + """ + if len(test_properties) == 0: + return + stub = LoggingSpecificationDocument_pb2_grpc.LoggingSpecificationDocumentStub(self._channel) + try: + stub.SetTestProperties( + LoggingSpecificationDocument_pb2.SetTestPropertiesRequest( + document_identifier=self._identifier, + test_properties=[self._convert_from_test_property(x) for x in test_properties] + ) + ) + except (RpcError, ValueError) as error: + self._raise_if_application_closed() + raise FlexLoggerError("Failed to set test properties") from error + def get_test_property(self, test_property_name: str) -> TestProperty: """Get the test property with the specified name. diff --git a/tests/assets/ProjectWithUpdatedLoggingPath/Channel Specification.flxio b/tests/assets/ProjectWithLoggingSpecification/Channel Specification.flxio similarity index 100% rename from tests/assets/ProjectWithUpdatedLoggingPath/Channel Specification.flxio rename to tests/assets/ProjectWithLoggingSpecification/Channel Specification.flxio diff --git a/tests/assets/ProjectWithUpdatedLoggingPath/Logging Specification.flxcfg b/tests/assets/ProjectWithLoggingSpecification/Logging Specification.flxcfg similarity index 50% rename from tests/assets/ProjectWithUpdatedLoggingPath/Logging Specification.flxcfg rename to tests/assets/ProjectWithLoggingSpecification/Logging Specification.flxcfg index 554895c..6814275 100644 --- a/tests/assets/ProjectWithUpdatedLoggingPath/Logging Specification.flxcfg +++ b/tests/assets/ProjectWithLoggingSpecification/Logging Specification.flxcfg @@ -1,15 +1,15 @@  - + - - - + + + - - + + bparrott diff --git a/tests/assets/ProjectWithUpdatedLoggingPath/ProjectWithUpdatedLoggingPath.flxproj b/tests/assets/ProjectWithLoggingSpecification/ProjectWithLoggingSpecification.flxproj similarity index 100% rename from tests/assets/ProjectWithUpdatedLoggingPath/ProjectWithUpdatedLoggingPath.flxproj rename to tests/assets/ProjectWithLoggingSpecification/ProjectWithLoggingSpecification.flxproj diff --git a/tests/assets/ProjectWithUpdatedLoggingPath/Screen.flxscr b/tests/assets/ProjectWithLoggingSpecification/Screen.flxscr similarity index 100% rename from tests/assets/ProjectWithUpdatedLoggingPath/Screen.flxscr rename to tests/assets/ProjectWithLoggingSpecification/Screen.flxscr diff --git a/tests/assets/ProjectWithUpdatedLoggingPath/Test Specification.flxtest b/tests/assets/ProjectWithLoggingSpecification/Test Specification.flxtest similarity index 100% rename from tests/assets/ProjectWithUpdatedLoggingPath/Test Specification.flxtest rename to tests/assets/ProjectWithLoggingSpecification/Test Specification.flxtest diff --git a/tests/test_logging_specification_document.py b/tests/test_logging_specification_document.py index 37daaf4..cbfb00f 100644 --- a/tests/test_logging_specification_document.py +++ b/tests/test_logging_specification_document.py @@ -31,7 +31,7 @@ class TestLoggingSpecificationDocument: def test__open_project__get_logging_path__logging_path_matches_user_setting( self, app: Application ) -> None: - with open_project(app, "ProjectWithUpdatedLoggingPath") as project: + with open_project(app, "ProjectWithLoggingSpecification") as project: logging_specification = project.open_logging_specification_document() assert r"C:\MyDataGoesHere" == logging_specification.get_log_file_base_path() @@ -39,7 +39,7 @@ def test__open_project__get_logging_path__logging_path_matches_user_setting( @pytest.mark.integration # type: ignore def test__open_project__set_logging_path__logging_path_updates(self, app: Application) -> None: - with open_project(app, "ProjectWithUpdatedLoggingPath") as project: + with open_project(app, "ProjectWithLoggingSpecification") as project: logging_specification = project.open_logging_specification_document() logging_specification.set_log_file_base_path(r"C:\MyDataGoesThere") @@ -107,6 +107,27 @@ def test__start_test_session__get_logging_name__no_exception_raised( name = logging_specification.get_log_file_name() assert name is not None + @pytest.mark.integration # type: ignore + def test__open_project__get_logging_description__logging_description_matches_user_setting( + self, app: Application + ) -> None: + with open_project(app, "ProjectWithLoggingSpecification") as project: + logging_specification = project.open_logging_specification_document() + + assert r"This is the description of the log file." == logging_specification.get_log_file_description() + + @pytest.mark.integration # type: ignore + def test__open_project__set_logging_description__logging_path_updates(self, app: Application) -> None: + with open_project(app, "ProjectWithLoggingSpecification") as project: + logging_specification = project.open_logging_specification_document() + + new_description = r"This is the new description of the log file." + # Precondition + assert new_description != logging_specification.get_log_file_description() + logging_specification.set_log_file_description(new_description) + + assert new_description == logging_specification.get_log_file_description() + @pytest.mark.integration # type: ignore def test__open_project__get_test_properties__all_properties_returned( self, app: Application, logging_spec_with_test_properties: LoggingSpecificationDocument @@ -124,6 +145,36 @@ def test__open_project__get_test_properties__all_properties_returned( ) self.assert_property_matches(properties[4], "Who you gonna call?", "Ghostbusters", False) + @pytest.mark.integration # type: ignore + def test__open_project__set_test_properties__all_properties_update( + self, app: Application, logging_spec_with_test_properties: LoggingSpecificationDocument + ) -> None: + # Precondition + properties = logging_spec_with_test_properties.get_test_properties() + assert 5 == len(properties) + # # Name Value Prompt_on_start + # 0 Operator bparrott false + # 1 DUT Serial number: ... true + # 2 Property string.Empty false + # 3 Best Configuration Based ... FlexLogger false + # 4 Who you gonna call? Ghostbusters false + logging_spec_with_test_properties.set_test_properties([ + TestProperty("Operator", "peteri", True), # change value and prompt + TestProperty("DUT", "12345", True), # change value + TestProperty("I cannot think", "of anything to put here", False) # add property + ]) + + properties = logging_spec_with_test_properties.get_test_properties() + assert 6 == len(properties) + self.assert_property_matches(properties[0], "Operator", "peteri", True) + self.assert_property_matches(properties[1], "DUT", "12345", True) + self.assert_property_matches(properties[2], "Property", "", False) + self.assert_property_matches( + properties[3], "Best Configuration Based Data Logging Software", "FlexLogger", False + ) + self.assert_property_matches(properties[4], "Who you gonna call?", "Ghostbusters", False) + self.assert_property_matches(properties[5], "I cannot think", "of anything to put here", False) + @pytest.mark.integration # type: ignore def test__open_project__get_test_properties__get_test_property_matches( self, app: Application, logging_spec_with_test_properties: LoggingSpecificationDocument