Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move to pyproject.toml #1726

Merged
merged 7 commits into from
Oct 24, 2024
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
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5530cc393682e555299ae444e692ccba9c616b2f
84 changes: 47 additions & 37 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,61 @@ name: Python package

on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches: [ master ]
branches: [master]

jobs:
build:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: Install uv
uses: astral-sh/setup-uv@v3

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install the project
run: |
uv sync --all-extras --dev
uv tool install pre-commit
- name: Lint with ruff
run: |
uvx pre-commit run -a

build:
runs-on: ubuntu-latest
needs: lint
strategy:
fail-fast: false
matrix:
python-version: ['3.7', '3.11', 'pypy-3.10']
python-version: ["3.9", "3.10", "pypy-3.10"]

steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pytest mypy ruff
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f dev_requirements.txt ]; then pip install -r dev_requirements.txt; fi
- name: Test with pytest
run: |
pytest -v -s
- uses: actions/checkout@v4
with:
submodules: true

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pre-commit
- name: Lint with ruff
run: |
pre-commit run -a
- name: Install uv
uses: astral-sh/setup-uv@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install the project
run: uv sync --all-extras --dev

- name: Install dependencies
run: |
uv tool install mypy
uv tool install ruff
- name: Run tests
run: uv run pytest -v -s tests
2 changes: 2 additions & 0 deletions asyncua/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
"""
Pure Python OPC-UA library
"""

import sys

if sys.version_info >= (3, 8):
from importlib import metadata
else:
Expand Down
47 changes: 15 additions & 32 deletions asyncua/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ def __init__(self, url: str, timeout: float = 4, watchdog_intervall: float = 1.0
"""
self._server_url = urlparse(url)
# take initial username and password from the url
userinfo, have_info, _ = self._server_url.netloc.rpartition('@')
userinfo, have_info, _ = self._server_url.netloc.rpartition("@")
if have_info:
username, have_password, password = userinfo.partition(':')
username, have_password, password = userinfo.partition(":")
self._username = unquote(username)
if have_password:
self._password = unquote(password)
Expand Down Expand Up @@ -111,7 +111,7 @@ def server_url(self) -> ParseResult:
is not recommended for security reasons.
"""
url = self._server_url
userinfo, have_info, hostinfo = url.netloc.rpartition('@')
userinfo, have_info, hostinfo = url.netloc.rpartition("@")
if have_info:
# remove credentials from url, preventing them to be sent unencrypted in e.g. send_hello
if self.strip_url_credentials:
Expand All @@ -125,7 +125,7 @@ def find_endpoint(endpoints: Iterable[ua.EndpointDescription], security_mode: ua
"""
_logger.info("find_endpoint %r %r %r", endpoints, security_mode, policy_uri)
for ep in endpoints:
if (ep.EndpointUrl.startswith(ua.OPC_TCP_SCHEME) and ep.SecurityMode == security_mode and ep.SecurityPolicyUri == policy_uri):
if ep.EndpointUrl.startswith(ua.OPC_TCP_SCHEME) and ep.SecurityMode == security_mode and ep.SecurityPolicyUri == policy_uri:
return ep
raise ua.UaError(f"No matching endpoints: {security_mode}, {policy_uri}")

Expand Down Expand Up @@ -171,8 +171,8 @@ async def set_security_string(self, string: str) -> None:
if len(parts) < 4:
raise ua.UaError(f"Wrong format: `{string}`, expected at least 4 comma-separated values")

if '::' in parts[3]: # if the filename contains a colon, assume it's a conjunction and parse it
parts[3], client_key_password = parts[3].split('::')
if "::" in parts[3]: # if the filename contains a colon, assume it's a conjunction and parse it
parts[3], client_key_password = parts[3].split("::")
else:
client_key_password = None

Expand Down Expand Up @@ -205,7 +205,7 @@ async def set_security(
# this generates a error in our crypto part, so we strip everything after
# the server cert. To do this we read byte 2:4 and get the length - 4
cert_len_idx = 2
len_bytestr = endpoint.ServerCertificate[cert_len_idx:cert_len_idx + 2]
len_bytestr = endpoint.ServerCertificate[cert_len_idx : cert_len_idx + 2]
cert_len = int.from_bytes(len_bytestr, byteorder="big", signed=False) + 4
server_certificate = uacrypto.x509_from_der(endpoint.ServerCertificate[:cert_len])
elif not isinstance(server_certificate, uacrypto.CertProperties):
Expand All @@ -224,7 +224,6 @@ async def _set_security(
server_cert: uacrypto.CertProperties,
mode: ua.MessageSecurityMode = ua.MessageSecurityMode.SignAndEncrypt,
) -> None:

if isinstance(server_cert, uacrypto.CertProperties):
server_cert = await uacrypto.load_certificate(server_cert.path_or_content, server_cert.extension)
cert = await uacrypto.load_certificate(certificate.path_or_content, certificate.extension)
Expand Down Expand Up @@ -500,7 +499,7 @@ async def create_session(self) -> ua.CreateSessionResult:
# this generates a error in our crypto part, so we strip everything after
# the server cert. To do this we read byte 2:4 and get the length - 4
cert_len_idx = 2
len_bytestr = response.ServerCertificate[cert_len_idx:cert_len_idx + 2]
len_bytestr = response.ServerCertificate[cert_len_idx : cert_len_idx + 2]
cert_len = int.from_bytes(len_bytestr, byteorder="big", signed=False) + 4
server_certificate = response.ServerCertificate[:cert_len]
if not self.security_policy.peer_certificate:
Expand Down Expand Up @@ -630,7 +629,7 @@ async def activate_session(self, username: Optional[str] = None, password: Optio
if self.security_policy.AsymmetricSignatureURI:
params.ClientSignature.Algorithm = self.security_policy.AsymmetricSignatureURI
else:
params.ClientSignature.Algorithm = (security_policies.SecurityPolicyBasic256.AsymmetricSignatureURI)
params.ClientSignature.Algorithm = security_policies.SecurityPolicyBasic256.AsymmetricSignatureURI
params.ClientSignature.Signature = self.security_policy.asymmetric_cryptography.signature(challenge)
params.LocaleIds = self._locale
if not username and not user_certificate:
Expand Down Expand Up @@ -729,9 +728,7 @@ def get_node(self, nodeid: Union[Node, ua.NodeId, str, int]) -> Node:
"""
return Node(self.uaclient, nodeid)

async def create_subscription(
self, period: Union[ua.CreateSubscriptionParameters, float], handler: SubscriptionHandler, publishing: bool = True
) -> Subscription:
async def create_subscription(self, period: Union[ua.CreateSubscriptionParameters, float], handler: SubscriptionHandler, publishing: bool = True) -> Subscription:
"""
Create a subscription.
Returns a Subscription object which allows to subscribe to events or data changes on server.
Expand Down Expand Up @@ -763,35 +760,21 @@ def get_subscription_revised_params(
params: ua.CreateSubscriptionParameters,
results: ua.CreateSubscriptionResult,
) -> Optional[ua.ModifySubscriptionParameters]:
if (
results.RevisedPublishingInterval == params.RequestedPublishingInterval
and results.RevisedLifetimeCount == params.RequestedLifetimeCount
and results.RevisedMaxKeepAliveCount == params.RequestedMaxKeepAliveCount
):
if results.RevisedPublishingInterval == params.RequestedPublishingInterval and results.RevisedLifetimeCount == params.RequestedLifetimeCount and results.RevisedMaxKeepAliveCount == params.RequestedMaxKeepAliveCount:
return None
_logger.warning(
"Revised values returned differ from subscription values: %s", results
)
_logger.warning("Revised values returned differ from subscription values: %s", results)
revised_interval = results.RevisedPublishingInterval
# Adjust the MaxKeepAliveCount based on the RevisedPublishInterval when necessary
new_keepalive_count = self.get_keepalive_count(revised_interval)
if (
revised_interval != params.RequestedPublishingInterval
and new_keepalive_count != params.RequestedMaxKeepAliveCount
):
_logger.info(
"KeepAliveCount will be updated to %s "
"for consistency with RevisedPublishInterval", new_keepalive_count
)
if revised_interval != params.RequestedPublishingInterval and new_keepalive_count != params.RequestedMaxKeepAliveCount:
_logger.info("KeepAliveCount will be updated to %s " "for consistency with RevisedPublishInterval", new_keepalive_count)
modified_params = ua.ModifySubscriptionParameters()
# copy the existing subscription parameters
copy_dataclass_attr(params, modified_params)
# then override with the revised values
modified_params.RequestedMaxKeepAliveCount = new_keepalive_count
modified_params.SubscriptionId = results.SubscriptionId
modified_params.RequestedPublishingInterval = (
results.RevisedPublishingInterval
)
modified_params.RequestedPublishingInterval = results.RevisedPublishingInterval
# update LifetimeCount but chances are it will be re-revised again
modified_params.RequestedLifetimeCount = results.RevisedLifetimeCount
return modified_params
Expand Down
Loading
Loading