Add create_grpc_client_channel API to enable integration with NI-TLS in our NI driver Python gRPC APIs - #3
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an optional gRPC channel factory to nitlsconfig that creates secure (TLS/mTLS) or insecure grpc.Channel instances based on NI-TLS configuration, and updates packaging/CI/docs to make grpcio an opt-in extra while expanding test coverage (including Python 3.9).
Changes:
- Introduces
nitlsconfig.grpc_channel.create_grpc_client_channelplus retry policy support. - Makes gRPC support optional via an extras dependency and lazy root-package exports.
- Adds substantial unit + “real object” + end-to-end TLS tests and updates CI matrices/install args.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_package_exports.py | Verifies public import surface, lazy exports, and that importing nitlsconfig doesn’t import grpc. |
| tests/unit/test_nitlsconfig.py | Extends config parsing assertions and adds tests that tie real config parsing to channel credential construction. |
| tests/unit/test_grpc_channel.py | Unit tests for target formatting, TLS decision logic, credential building, and retry policy option generation (with mocked gRPC constructors). |
| tests/unit/test_grpc_channel_tls.py | End-to-end mutual TLS handshake tests against an in-process gRPC server with generated certs. |
| tests/unit/test_grpc_channel_real.py | Ensures the factory returns real grpc.Channel objects and that gRPC accepts the constructed options/credentials. |
| tests/unit/fake_config.py | Shared ClientConfig test double for TLS scenarios without invoking the CLI. |
| tests/unit/certificates.py | Generates ephemeral CA/client/server certificates for TLS handshake tests. |
| src/nitlsconfig/grpc_channel.py | New gRPC channel factory and retry-policy plumbing based on NI-TLS configuration. |
| src/nitlsconfig/cli.py | Adds ClientConfig.server_mode plus key location/contents accessors needed by the gRPC factory. |
| src/nitlsconfig/init.py | Adds __version__, documents optional gRPC support, and lazily re-exports gRPC factory symbols. |
| README.md | Documents installing with/without extras and shows usage examples for channel creation + retries. |
| pyproject.toml | Adds grpc optional-dependency extra, updates metadata/keywords/classifiers, and adds test dependency on cryptography. |
| poetry.lock | Locks new dependencies introduced for optional gRPC and TLS tests. |
| docs/index.rst | Updates documentation title to match the package. |
| CONTRIBUTING.md | Updates release title guidance to use nitlsconfig name. |
| .github/workflows/run_unit_tests.yml | Adds Python 3.9 to the matrix, installs with --all-extras, and adds a “no extras” install verification job. |
| .github/workflows/publish.yml | Updates published package URL path from pypi-nitlsconfig to nitlsconfig. |
| .github/workflows/check_module.yml | Adds Python 3.9 and installs with --all-extras for analysis/linting. |
| .github/ISSUE_TEMPLATE/bug_report.md | Updates template to refer to nitlsconfig version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The package root re-exports names from nitlsconfig.cli and nitlsconfig.grpc_channel. AutoAPI's default options include imported-members, so those names were documented in two places, making a bare cross-reference ambiguous and failing the -W build in check_docs.
Drop references to NI's internal C++ TLS transports from module docs and test comments, keeping the customer-relevant rationale. Replace the internal build path prefix in the test fixtures with the install location; tests only assert on leaf file names and schemes, so behavior is unchanged.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 21 out of 22 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
src/nitlsconfig/grpc_channel.py:90
TlsConfigurationErrorrepresents a successfully-read but invalid TLS configuration, but it subclassesNitlsconfigCliError, whose contract is “command invocation failures”. This makes exception handling ambiguous (catchingNitlsconfigCliErrorwould also catch configuration errors) and conflicts with the docstring/"Raises" separation increate_grpc_client_channel.
class TlsConfigurationError(NitlsconfigCliError):
"""Raised when the NI-TLS configuration was read successfully but is invalid."""
src/nitlsconfig/init.py:96
__getattr__catches anyImportErrorfrom importingnitlsconfig.grpc_channeland re-raises a “grpcio is not installed” message. That will also mask unrelated import problems insidegrpc_channel(or its dependencies) and mislead users during debugging. Prefer only translating the error when the missing module is actuallygrpc/grpcio, and re-raise otherwise.
try:
from nitlsconfig import grpc_channel
except ImportError as exc: # pragma: no cover - requires an install without the extra
raise ImportError(
f"nitlsconfig.{name} requires grpcio, which is not installed. "
"Install it with: pip install nitlsconfig[grpc]"
) from exc
return getattr(grpc_channel, name)
pkthong
reviewed
Jul 30, 2026
pkthong
reviewed
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this Pull Request accomplish?
This PR will:
Note: We are very intentionally only supporting gRPC channel creation for ease-of-use within our NI gRPC Python APIs. Any other transports or generic interface to NI-TLS in Python would need to be an intentional customer request or even customer open source update because they desire it.
Why should this Pull Request be merged?
Our Python APIs from nimi-python and nidaqmx-python all take a separate gRPC channel as part of the session constructor's parameter set that lets users setup their own custom gRPC channel that can be insecure or secure. This is mostly fine, but now that NI is introducing first-class mTLS capabilities to our drivers using our own custom certificate management framework (NI-TLS), we want to make it fully streamlined for customers to create gRPC channels using NI-TLS for setting up mTLS secured channels and provide some extra niceties such as a consistent retry policy with our LabVIEW API.
Minor fixes are some additional cleanup.
Lastly, ensure that the gRPC support here is actually optional because:
What testing has been done?
Added a comprehensive set of pytests that: