Skip to content

Commit

Permalink
CONTRIBUTING.md: Add info on running linters and simplify mypy invoca…
Browse files Browse the repository at this point in the history
…tion (#612)

* CONTRIBUTING.md: Add info on running linters

* pyproject.toml: Specify mypy files to check

* handwritten: Fix tzinfo type hints

tests\unit\test_lib_time.py:109: error: Argument "tzinfo" to "to_datetime" of "AbsoluteTime" has incompatible type "ZoneInfo"; expected "Optional[timezone]"  [arg-type]
tests\unit\test_grpc_time.py:132: error: Argument "tzinfo" to "convert_timestamp_to_time" has incompatible type "ZoneInfo"; expected "Optional[timezone]"  [arg-type]

* tests: Fix type hints and a mypy-identified test bug

tests\component\test_watchdog.py:10: error: "Task" not callable  [operator]
tests\component\test_watchdog.py:41: error: "Task" not callable  [operator]
tests\component\test_watchdog.py:67: error: "Task" not callable  [operator]
tests\component\test_interpreter.py:45: error: Invalid index type "int" for "dict[DAQmxErrors, str]"; expected type "DAQmxErrors"  [index]
tests\component\task\test_in_stream_read_properties.py:139: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Path]")  [assignment]
tests\component\task\test_in_stream_read_properties.py:159: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Path]")  [assignment]
tests\component\task\channels\test_channel_properties.py:216: error: "Scale" has no attribute "load"  [attr-defined]
tests\acceptance\test_multi_threading.py:126: error: Argument 4 to "submit" of "Executor" has incompatible type "Task"; expected "AIChannel"  [arg-type]
tests\acceptance\test_multi_threading.py:135: error: Argument 4 to "submit" of "Executor" has incompatible type "Task"; expected "AIChannel"  [arg-type]
tests\acceptance\test_internationalization.py:69: error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Path]")  [assignment]
tests\unit\test_task_events.py:40: error: Argument 3 to "register_event_handlers" has incompatible type "type[_TaskEventType]"; expected "Sequence[_TaskEventType]"  [arg-type]
tests\unit\test_task_events.py:56: error: Argument 3 to "register_event_handlers" has incompatible type "type[_TaskEventType]"; expected "Sequence[_TaskEventType]"  [arg-type]
tests\unit\test_task_events.py:71: error: Argument 3 to "register_event_handlers" has incompatible type "type[_TaskEventType]"; expected "Sequence[_TaskEventType]"  [arg-type]
tests\unit\test_task.py:46: error: "Callable[[Optional[GrpcSessionOptions], Optional[BaseInterpreter]], BaseInterpreter]" has no attribute "mock"  [attr-defined]

* CONTRIBUTING.md: Simplify mypy invocation

* GitHub: Simplify mypy invocation

* tests: Remove an unused import

* pyproject.toml: Point mypy to the parent of the nidaqmx package, not inside the package itself

* tests: Add imports that mypy --platform complains about

* tests: Fix Python 3.8 error
  • Loading branch information
bkeryan authored Jul 10, 2024
1 parent 570c62b commit 422c9b7
Show file tree
Hide file tree
Showing 32 changed files with 72 additions and 39 deletions.
11 changes: 3 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,11 @@ jobs:
python -m pip install --upgrade pip
poetry install --all-extras
- name: Run linters
run: |
poetry run ni-python-styleguide lint
run: poetry run ni-python-styleguide lint
- name: Run mypy (Linux)
run: |
poetry run mypy generated/nidaqmx
poetry run mypy tests
run: poetry run mypy
- name: Run mypy (Windows)
run: |
poetry run mypy generated/nidaqmx --platform win32
poetry run mypy tests --platform win32
run: poetry run mypy --platform win32
- name: Generate ni-daqmx files
run: |
rm -fr generated/nidaqmx
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ through our [GitHub issues page](http://github.com/ni/nidaqmx-python/issues).
> The codegen scripts require Python 3.8 or later.
8. Run all the regression tests again (including the tests you just added), and confirm that they all
pass.
9. Send a GitHub Pull Request to the main repository's master branch. GitHub Pull Requests are the
9. Run `poetry run ni-python-styleguide lint` to check that the updated code follows NI's Python coding
conventions. If this reports errors, first run `poetry run ni-python-styleguide fix` in order to sort
imports and format the code with Black, then manually fix any remaining errors.
10. Run `poetry run mypy` to statically type-check the updated code.
11. Send a GitHub Pull Request to the main repository's master branch. GitHub Pull Requests are the
expected method of code collaboration on this project.

# Testing
Expand Down
3 changes: 2 additions & 1 deletion generated/nidaqmx/_grpc_time.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import timezone
from datetime import datetime as std_datetime
from datetime import tzinfo as dt_tzinfo
from hightime import datetime as ht_datetime
from hightime import timedelta as ht_timedelta
from typing import Optional, Union
Expand Down Expand Up @@ -41,7 +42,7 @@ def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: Optional
ts.FromNanoseconds(seconds_since_1970 * _NS_PER_S + nanos)
return ts

def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = None) -> ht_datetime:
def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[dt_tzinfo] = None) -> ht_datetime:
total_nanos = ts.ToNanoseconds()
seconds, nanos = divmod(total_nanos, _NS_PER_S)
# Convert the nanoseconds to yoctoseconds.
Expand Down
3 changes: 2 additions & 1 deletion generated/nidaqmx/_lib_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import functools
from datetime import timezone
from datetime import datetime as std_datetime
from datetime import tzinfo as dt_tzinfo
from hightime import datetime as ht_datetime
from hightime import timedelta as ht_timedelta
from typing import Optional, Union
Expand Down Expand Up @@ -54,7 +55,7 @@ def from_datetime(cls, dt: Union[std_datetime, ht_datetime]) -> AbsoluteTime:

return AbsoluteTime(lsb=lsb, msb=seconds_since_1904)

def to_datetime(self, tzinfo: Optional[timezone] = None) -> ht_datetime:
def to_datetime(self, tzinfo: Optional[dt_tzinfo] = None) -> ht_datetime:
total_yoctoseconds = int(
round(AbsoluteTime._YS_PER_S * self.lsb / AbsoluteTime._NUM_SUBSECONDS)
)
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ requires = ["poetry>=1.2"]
build-backend = "poetry.masonry.api"

[tool.mypy]
files = "generated/,tests/"
check_untyped_defs = true
namespace_packages = true
plugins = "numpy.typing.mypy_plugin"
Expand Down
3 changes: 2 additions & 1 deletion src/handwritten/_grpc_time.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import timezone
from datetime import datetime as std_datetime
from datetime import tzinfo as dt_tzinfo
from hightime import datetime as ht_datetime
from hightime import timedelta as ht_timedelta
from typing import Optional, Union
Expand Down Expand Up @@ -41,7 +42,7 @@ def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: Optional
ts.FromNanoseconds(seconds_since_1970 * _NS_PER_S + nanos)
return ts

def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = None) -> ht_datetime:
def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[dt_tzinfo] = None) -> ht_datetime:
total_nanos = ts.ToNanoseconds()
seconds, nanos = divmod(total_nanos, _NS_PER_S)
# Convert the nanoseconds to yoctoseconds.
Expand Down
3 changes: 2 additions & 1 deletion src/handwritten/_lib_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import functools
from datetime import timezone
from datetime import datetime as std_datetime
from datetime import tzinfo as dt_tzinfo
from hightime import datetime as ht_datetime
from hightime import timedelta as ht_timedelta
from typing import Optional, Union
Expand Down Expand Up @@ -54,7 +55,7 @@ def from_datetime(cls, dt: Union[std_datetime, ht_datetime]) -> AbsoluteTime:

return AbsoluteTime(lsb=lsb, msb=seconds_since_1904)

def to_datetime(self, tzinfo: Optional[timezone] = None) -> ht_datetime:
def to_datetime(self, tzinfo: Optional[dt_tzinfo] = None) -> ht_datetime:
total_yoctoseconds = int(
round(AbsoluteTime._YS_PER_S * self.lsb / AbsoluteTime._NUM_SUBSECONDS)
)
Expand Down
1 change: 1 addition & 0 deletions tests/acceptance/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pytest

import nidaqmx
import nidaqmx.system

EXAMPLES_DIRECTORY = Path(__file__).parent.parent.parent / "examples"
EXAMPLE_PATHS = [p for p in EXAMPLES_DIRECTORY.glob("**/*.py") if p.name != "__init__.py"]
Expand Down
2 changes: 1 addition & 1 deletion tests/acceptance/test_internationalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@ def test___supported_encoding___logging_file_path___returns_assigned_value(
):
if _get_encoding(ai_task) not in supported_encodings:
pytest.skip("requires compatible encoding")
ai_task.in_stream.logging_file_path = file_path
ai_task.in_stream.logging_file_path = file_path # type: ignore[assignment] # https://github.com/ni/nidaqmx-python/issues/613

assert ai_task.in_stream.logging_file_path == pathlib.Path(file_path)
6 changes: 3 additions & 3 deletions tests/acceptance/test_multi_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test___multiple_tasks___get_set_float_and_string_properties___no_errors(
futures = []
for i in range(num_tasks):
task = generate_task()
task.ai_channels.add_ai_voltage_chan(
channel = task.ai_channels.add_ai_voltage_chan(
multi_threading_test_devices[i].ai_physical_chans[0].name, min_val=-1.0, max_val=1.0
)
tasks.append(task)
Expand All @@ -123,7 +123,7 @@ def test___multiple_tasks___get_set_float_and_string_properties___no_errors(
_get_set_property_thread_main,
start_barrier,
stop_semaphore,
task,
channel,
"ai_max",
[1.0, 2.0, 5.0, 10.0],
)
Expand All @@ -132,7 +132,7 @@ def test___multiple_tasks___get_set_float_and_string_properties___no_errors(
_get_set_property_thread_main,
start_barrier,
stop_semaphore,
task,
channel,
"description",
["ABC", "DEF", "GHI", "JKL"],
)
Expand Down
1 change: 1 addition & 0 deletions tests/component/system/storage/test_persisted_channel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.system.storage import PersistedChannel


Expand Down
4 changes: 2 additions & 2 deletions tests/component/task/channels/test_channel_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
RTDType,
VoltageUnits,
)
from nidaqmx.scale import Scale
from nidaqmx.system.storage import PersistedScale
from nidaqmx.task.channels import AIChannel, CIChannel


Expand Down Expand Up @@ -211,7 +211,7 @@ def test___channel_with_scale___get_scale_property___shared_interpreter(

@pytest.mark.scale_name("polynomial_scale")
def test___channel_with_scale___set_scale_property___returns_assigned_scale(
ai_voltage_chan_with_scale: AIChannel, persisted_scale: Scale
ai_voltage_chan_with_scale: AIChannel, persisted_scale: PersistedScale
):
ai_voltage_chan_with_scale.ai_custom_scale = persisted_scale.load()

Expand Down
1 change: 1 addition & 0 deletions tests/component/task/test_in_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import AcquisitionType

# With a simulated X Series, setting ai_max/min to +/-2.5 V coerces the hardware range
Expand Down
4 changes: 2 additions & 2 deletions tests/component/task/test_in_stream_read_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def test___ai_task___get_string_property___returns_default_value(ai_task: Task):
raises=DaqError,
)
def test___ai_task___set_string_property___returns_assigned_value(ai_task: Task):
ai_task.in_stream.logging_file_path = "TestData.tdms"
ai_task.in_stream.logging_file_path = "TestData.tdms" # type: ignore[assignment] # https://github.com/ni/nidaqmx-python/issues/613

assert ai_task.in_stream.logging_file_path == pathlib.Path("TestData.tdms")

Expand All @@ -156,7 +156,7 @@ def test___ai_task___set_string_property_none___returns_default_value(ai_task: T
raises=DaqError,
)
def test___ai_task___reset_string_property___returns_default_value(ai_task: Task):
ai_task.in_stream.logging_file_path = "TestData.tdms"
ai_task.in_stream.logging_file_path = "TestData.tdms" # type: ignore[assignment] # https://github.com/ni/nidaqmx-python/issues/613

del ai_task.in_stream.logging_file_path

Expand Down
1 change: 1 addition & 0 deletions tests/component/task/test_out_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest

import nidaqmx
import nidaqmx.system


@pytest.fixture(params=[1, 2])
Expand Down
2 changes: 1 addition & 1 deletion tests/component/test_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test___grpc_channel_with_errors___get_error_string___returns_failed_to_retri
@pytest.mark.grpc_only(reason="Tests gRPC-specific error message lookup")
@pytest.mark.parametrize("error_code", list(_ERROR_MESSAGES))
def test___error_code_with_hardcoded_error_message___get_error_string___returns_hardcoded_error_message(
interpreter: BaseInterpreter, error_code: int
interpreter: BaseInterpreter, error_code: DAQmxErrors
) -> None:
error_message = interpreter.get_error_string(error_code)

Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_readers_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.stream_readers import (
AnalogMultiChannelReader,
AnalogSingleChannelReader,
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_readers_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.stream_readers import CounterReader

SIGNAL_TO_MEASURE = "100kHzTimebase"
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_readers_di.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import LineGrouping
from nidaqmx.stream_readers import (
DigitalMultiChannelReader,
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.stream_writers import AnalogMultiChannelWriter, AnalogSingleChannelWriter


Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_writers_ao.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.stream_writers import (
AnalogMultiChannelWriter,
AnalogSingleChannelWriter,
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_writers_co.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import AcquisitionType
from nidaqmx.stream_writers import CounterWriter
from nidaqmx.types import CtrFreq, CtrTick, CtrTime
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_stream_writers_do.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import LineGrouping
from nidaqmx.stream_writers import DigitalMultiChannelWriter, DigitalSingleChannelWriter
from nidaqmx.utils import flatten_channel_string
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_task.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import ShuntCalSelect, ShuntCalSource, ShuntElementLocation
from nidaqmx.error_codes import DAQmxErrors
from nidaqmx.errors import RpcError
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_task_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import AcquisitionType, EveryNSamplesEventType, Signal
from nidaqmx.error_codes import DAQmxErrors
from nidaqmx.errors import DaqResourceWarning, RpcError
Expand Down
1 change: 1 addition & 0 deletions tests/component/test_task_read_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest

import nidaqmx
import nidaqmx.system
from nidaqmx.constants import AcquisitionType


Expand Down
17 changes: 12 additions & 5 deletions tests/component/test_watchdog.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from nidaqmx import Task
from typing import Callable

from nidaqmx.constants import WatchdogAOExpirState, WatchdogCOExpirState
from nidaqmx.system import Device
from nidaqmx.system.watchdog import AOExpirationState, COExpirationState
from nidaqmx.system.watchdog import AOExpirationState, COExpirationState, WatchdogTask


def test___watchdog_task___cfg_watchdog_ao_expir_states___no_error(
generate_watchdog_task: Task, sim_9189_device: Device, sim_9263_device: Device
generate_watchdog_task: Callable[..., WatchdogTask],
sim_9189_device: Device,
sim_9263_device: Device,
):
watchdog_task = generate_watchdog_task(f"{sim_9189_device.name}", timeout=0.8)
expir_states = [
Expand Down Expand Up @@ -36,7 +39,9 @@ def test___watchdog_task___cfg_watchdog_ao_expir_states___no_error(


def test___watchdog_task___cfg_watchdog_co_expir_states___no_error(
generate_watchdog_task: Task, sim_9189_device: Device, sim_9401_device: Device
generate_watchdog_task: Callable[..., WatchdogTask],
sim_9189_device: Device,
sim_9401_device: Device,
):
watchdog_task = generate_watchdog_task(f"{sim_9189_device.name}", timeout=0.8)
expir_states = [
Expand All @@ -62,7 +67,9 @@ def test___watchdog_task___cfg_watchdog_co_expir_states___no_error(


def test___watchdog_task___clear_expiration___no_error(
generate_watchdog_task: Task, sim_9189_device: Device, sim_9263_device: Device
generate_watchdog_task: Callable[..., WatchdogTask],
sim_9189_device: Device,
sim_9263_device: Device,
):
watchdog_task = generate_watchdog_task(f"{sim_9189_device.name}", timeout=0.8)
expir_states = [
Expand Down
Loading

0 comments on commit 422c9b7

Please sign in to comment.