Skip to content

Add create_grpc_client_channel API to enable integration with NI-TLS in our NI driver Python gRPC APIs - #3

Merged
alexdubois-ni merged 5 commits into
mainfrom
users/adubois/addgRPCClientChannelFactory
Aug 3, 2026
Merged

alexdubois-ni merged 5 commits into
mainfrom
users/adubois/addgRPCClientChannelFactory

Conversation

@alexdubois-ni

@alexdubois-ni alexdubois-ni commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

What does this Pull Request accomplish?

This PR will:

  1. Add a new create_grpc_client_channel API from this package that will let our NI driver Python APIs with gRPC support users to easily create a secure or insecure channel based off their NI-TLS configurations.
  2. Provide some additional minor corrections to the original change set such as extending testing to Python 3.9 which is our minimum version (and NI-DAQmx's Python APIs as well)
  3. Make the grpc support an extra of this package.

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:

  1. We do not want to always pull in grpcio. There might be customers who only want to use the CLI aspect for working with nitlsconfig natively in Python.
  2. We might want to extend this to other protocols and technologies in the future. Let's not make ourselves fully tied to gRPC.

What testing has been done?

Added a comprehensive set of pytests that:

  1. Perform unit testing of the gRPC channels.
  2. Do a near vertical slice real testing against a simple gRPC server and creating client connections against it.

@alexdubois-ni
alexdubois-ni requested a review from Copilot July 30, 2026 18:26
@alexdubois-ni alexdubois-ni changed the title Users/adubois/addg rpc client channel factory Add create_grpc_client_channel API to enable integration with NI-TLS in our NI driver Python gRPC APIs Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

Test Results

 12 files  +  2   12 suites  +2   13s ⏱️ +11s
 47 tests + 43   47 ✅ + 43  0 💤 ±0  0 ❌ ±0 
564 runs  +524  564 ✅ +524  0 💤 ±0  0 ❌ ±0 

Results for commit 778789b. ± Comparison against base commit df6d63f.

♻️ This comment has been updated with latest results.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_channel plus 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.

Comment thread src/nitlsconfig/grpc_channel.py
Comment thread src/nitlsconfig/grpc_channel.py
Comment thread src/nitlsconfig/__init__.py Outdated
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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • TlsConfigurationError represents a successfully-read but invalid TLS configuration, but it subclasses NitlsconfigCliError, whose contract is “command invocation failures”. This makes exception handling ambiguous (catching NitlsconfigCliError would also catch configuration errors) and conflicts with the docstring/"Raises" separation in create_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 any ImportError from importing nitlsconfig.grpc_channel and re-raises a “grpcio is not installed” message. That will also mask unrelated import problems inside grpc_channel (or its dependencies) and mislead users during debugging. Prefer only translating the error when the missing module is actually grpc/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)

Comment thread README.md
Comment thread src/nitlsconfig/grpc_channel.py
Comment thread src/nitlsconfig/grpc_channel.py
@alexdubois-ni
alexdubois-ni requested a review from pkthong August 3, 2026 14:25

@ckoellin ckoellin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@pkthong pkthong left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@alexdubois-ni
alexdubois-ni merged commit 92932c3 into main Aug 3, 2026
30 checks passed
@pkthong
pkthong deleted the users/adubois/addgRPCClientChannelFactory branch August 4, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants