Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ Search open/closed issues before submitting. Someone may have reported the same

<!--- Include as many relevant details as possible about the environment you experienced the bug in -->

* `pypi-nitlsconfig` version
* `nitlsconfig` version
* Python version
4 changes: 2 additions & 2 deletions .github/workflows/check_module.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
python-version: ["3.10", 3.13, 3.14]
python-version: ["3.9", "3.10", 3.13, 3.14]
runs-on: ${{ matrix.os }}
steps:
- name: Check out repo
Expand All @@ -25,6 +25,6 @@ jobs:
- name: Analyze Python Project
uses: ni/python-actions/analyze-project@aa64e60612cb078b0c2ada666becbd70d4817d55 # 0.7.1
with:
install-args: "--with test --with lint"
install-args: "--with test --with lint --all-extras"
- name: Bandit security checks
run: poetry run bandit -c pyproject.toml -r src/nitlsconfig
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
environment:
# This logic is duplicated because `name` doesn't support the `env` context.
name: ${{ github.event_name == 'release' && 'pypi' || inputs.environment }}
url: ${{ fromJson(env.environment-info)[env.environment].base-url }}/p/pypi-nitlsconfig
url: ${{ fromJson(env.environment-info)[env.environment].base-url }}/p/nitlsconfig
permissions:
id-token: write
steps:
Expand Down
39 changes: 37 additions & 2 deletions .github/workflows/run_unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest]
python-version: ["3.10", 3.11, 3.12, 3.13, 3.14]
python-version: ["3.9", "3.10", 3.11, 3.12, 3.13, 3.14]
# Fail-fast skews the pass/fail ratio and seems to make pytest produce
# incomplete JUnit XML results.
fail-fast: false
Expand All @@ -31,7 +31,7 @@ jobs:
path: .venv
key: nitlsconfig-${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('poetry.lock') }}
- name: Install nitlsconfig
run: poetry install -v
run: poetry install -v --all-extras
- name: Run unit tests and code coverage
run: poetry run pytest ./tests/unit -v --cov=nitlsconfig --junitxml=test_results/nitlsconfig-${{ matrix.os }}-py${{ matrix.python-version }}.xml
- name: Upload test results
Expand All @@ -40,3 +40,38 @@ jobs:
name: test_results_unit_${{ matrix.os }}_py${{ matrix.python-version }}
path: ./test_results/*.xml
if: always()

check_install_without_extras:
name: Check install without extras
# grpcio is an optional extra. Without this job, nothing stops a top-level
# "import grpc" from creeping into the config-reading code and silently
# making the extra mandatory again.
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python
uses: ni/python-actions/setup-python@aa64e60612cb078b0c2ada666becbd70d4817d55 # 0.7.1
with:
python-version: "3.13"
- name: Install nitlsconfig without extras
run: pip install .
- name: Verify grpcio is absent
run: |
if pip show grpcio > /dev/null 2>&1; then
echo "grpcio was installed without the grpc extra"
exit 1
fi
- name: Verify the package imports and fails helpfully
run: |
python - <<'PY'
import nitlsconfig

assert nitlsconfig.ClientConfig is not None
try:
nitlsconfig.create_grpc_client_channel
except ImportError as exc:
assert "pip install nitlsconfig[grpc]" in str(exc), exc
else:
raise AssertionError("expected ImportError without the grpc extra")
PY
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ in the pypi-nitlsconfig repo. Here are the steps to follow to publish the packag

1. From the main GitHub repo page, select "Create a new release".
2. On the "New Release" page, create a new tag using the "Select Tag" drop down. The tag must be the package version, matching the value found in pyproject.toml. Example: `1.0.0`.
3. Enter a title in the "Release title" field. The title should contain the package name and version in the format `pypi-nitlsconfig <package-version>`. For example: `pypi-nitlsconfig 1.0.0`.
3. Enter a title in the "Release title" field. The title should contain the package name and version in the format `nitlsconfig <package-version>`. For example: `nitlsconfig 1.0.0`.
4. Click "Generate release notes" and edit the release notes.
- Delete entries for PRs that do not affect users, such as "chore(deps):" and "fix(deps):" PRs.
- Consider grouping related entries.
Expand Down
49 changes: 45 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,57 @@
# pypi-nitlsconfig
# nitlsconfig

Python API that reads nitlsconfig configurations through `nitlsconfig` command line.
Python API that reads nitlsconfig configurations through the `nitlsconfig` command line,
and builds gRPC client channels from them.

Installed and imported as `nitlsconfig`; developed at
[ni/pypi-nitlsconfig](https://github.com/ni/pypi-nitlsconfig).

## Runtime dependencies

- nitlsconfig executable, discoverable, or explicit path to NITLSCONFIG_CLI

## Install

- pip install nitlsconfig
Reading NI-TLS configuration is pure Python and has no third-party dependencies:

- `pip install nitlsconfig`

The gRPC channel factory additionally needs grpcio, which is an optional extra:

- `pip install nitlsconfig[grpc]`

## Creating a gRPC channel

`create_grpc_client_channel` reads the local NI-TLS client configuration and returns a
`grpc.Channel` secured accordingly. Pass it straight to any NI gRPC Python API:

```python
import nidcpower
import nitlsconfig

with nitlsconfig.create_grpc_client_channel("localhost", 31763) as channel:
options = nidcpower.GrpcSessionOptions(channel, "")
with nidcpower.Session("Dev1", grpc_options=options) as session:
...
```

The channel is mutually authenticated, one-way TLS, or insecure depending on how
the machine is configured; no code change is needed to move between them. The
channel is owned by the caller - NI driver APIs never close it.

Retries are opt-in:

```python
channel = nitlsconfig.create_grpc_client_channel(
Comment thread
alexdubois-ni marked this conversation as resolved.
"localhost", 31763, retry_policy=nitlsconfig.RetryPolicy()
)
```

`TlsConfigurationError` is raised when TLS is enabled but the configuration is
unusable. Accessing any of these names without the `grpc` extra installed raises
`ImportError` telling you which extra to install.

## Usage
## Reading configurations
```python
import nitlsconfig

Expand Down
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
# tell autoapi to doc the public options
autoapi_options = list(autoapi.extension._DEFAULT_OPTIONS)
autoapi_options.remove("private-members") # note: remove this to include "_" members in docs
# The package root re-exports names from nitlsconfig.cli and nitlsconfig.grpc_channel.
# Documenting those imports as well would define every name twice, which makes any
# cross-reference to a bare name ambiguous and fails the -W build.
autoapi_options.remove("imported-members")
autoapi_dirs = [root_path / "src" / "nitlsconfig"]
autoapi_type = "python"
autodoc_typehints = "description"
Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NI Panel Python API
===================
nitlsconfig Python API
======================
.. toctree::
:maxdepth: 3

Expand Down
Loading
Loading