Skip to content

Commit e23f517

Browse files
committed
Merge Pull Request 15 and Fix Issues 11, 12, 13
<rev> Merging pull request - "Fix for unregistering callbacks" #15 <rev> Fixing issue - "Should `_import_lib` error for unsupported platforms?" #13 <rev> Fixing issue - "Cannot catch load/version issues with public API" #12 <rev> Fixing issue - "CONTRIBUTING.rst link to Issues is broken" #11
1 parent 4da23ab commit e23f517

13 files changed

+192
-38
lines changed

CONTRIBUTING.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ To contribute to this project, it is recommended that you follow these steps:
2323
2. Run the unit tests on your system (see Testing section). At this point,
2424
if any tests fail, do not begin development. Try to investigate these
2525
failures. If you're unable to do so, report an issue through our
26-
`GitHub issues page <http://github.com/nidaqmx/issues>`_.
26+
`GitHub issues page <http://github.com/ni/nidaqmx-python/issues>`_.
2727
3. Write new tests that demonstrate your bug or feature. Ensure that these
2828
new tests fail.
2929
4. Make your change.
@@ -97,5 +97,5 @@ By making a contribution to this project, I certify that:
9797

9898
(taken from `developercertificate.org <http://developercertificate.org/>`_)
9999

100-
See `LICENSE <https://github.com/ni/nidaqmx/blob/master/LICENSE>`_
100+
See `LICENSE <https://github.com/ni/nidaqmx-python/blob/master/LICENSE>`_
101101
for details about how **nidaqmx** is licensed.

docs/conf.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
# add these directories to sys.path here. If the directory is relative to the
1717
# documentation root, use os.path.abspath to make it absolute, like shown here.
1818
#
19-
# import os
20-
# import sys
21-
# sys.path.insert(0, os.path.abspath('.'))
19+
import os
20+
import sys
21+
sys.path.insert(0, os.path.abspath('../'))
2222

2323

2424
# -- General configuration ------------------------------------------------

nidaqmx/_lib.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
from ctypes.util import find_library
1111
from numpy.ctypeslib import ndpointer
1212

13-
14-
class Error(Exception):
15-
pass
13+
from nidaqmx.errors import Error
1614

1715

1816
class DaqNotFoundError(Error):
@@ -68,7 +66,7 @@ def wrapped_ndpointer(*args, **kwargs):
6866
if 'flags' in kwargs:
6967
kwargs['flags'] = tuple(
7068
f.encode('ascii') for f in kwargs['flags'])
71-
69+
7270
base = ndpointer(*args, **kwargs)
7371

7472
def from_param(cls, obj):
@@ -208,6 +206,11 @@ def _import_lib(self):
208206
'Could not find an installation of NI-DAQmx. Please '
209207
'ensure that NI-DAQmx is installed on this machine or '
210208
'contact National Instruments for support.')
209+
else:
210+
raise DaqNotFoundError(
211+
'NI-DAQmx Python is not supported on this platform: {0}. '
212+
'Please direct any questions or feedback to National '
213+
'Instruments.'.format(sys.platform))
211214

212215
self._windll = DaqFunctionImporter(windll)
213216
self._cdll = DaqFunctionImporter(cdll)

nidaqmx/errors.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import ctypes
77
import warnings
88

9-
from nidaqmx._lib import lib_importer, ctypes_byte_str
109
from nidaqmx.error_codes import DAQmxErrors, DAQmxWarnings
1110

1211
__all__ = ['DaqError', 'DaqWarning', 'DaqResourceWarning']
@@ -113,6 +112,8 @@ class _ResourceWarning(Warning):
113112

114113

115114
def check_for_error(error_code):
115+
from nidaqmx._lib import lib_importer
116+
116117
if error_code < 0:
117118
error_buffer = ctypes.create_string_buffer(2048)
118119

nidaqmx/task.py

+37-21
Original file line numberDiff line numberDiff line change
@@ -717,16 +717,20 @@ def register_done_event(self, callback_method):
717717
ctypes.c_int32, lib_importer.task_handle, ctypes.c_int32,
718718
ctypes.c_void_p)
719719

720+
cfunc = lib_importer.windll.DAQmxRegisterDoneEvent
721+
cfunc.argtypes = [
722+
lib_importer.task_handle, ctypes.c_uint, DAQmxDoneEventCallbackPtr,
723+
ctypes.c_void_p]
724+
720725
if callback_method is not None:
721726
callback_method_ptr = DAQmxDoneEventCallbackPtr(callback_method)
722727
self._done_event_callbacks.append(callback_method_ptr)
723728
else:
724729
del self._done_event_callbacks[:]
725-
726-
cfunc = lib_importer.windll.DAQmxRegisterDoneEvent
727-
cfunc.argtypes = [
728-
lib_importer.task_handle, ctypes.c_uint, DAQmxDoneEventCallbackPtr,
729-
ctypes.c_void_p]
730+
callback_method_ptr = None
731+
cfunc.argtypes = [
732+
lib_importer.task_handle, ctypes.c_uint, ctypes.c_void_p,
733+
ctypes.c_void_p]
730734

731735
error_code = cfunc(
732736
self._handle, 0, callback_method_ptr, None)
@@ -770,18 +774,22 @@ def register_every_n_samples_acquired_into_buffer_event(
770774
ctypes.c_int32, lib_importer.task_handle, ctypes.c_int32,
771775
ctypes.c_uint32, ctypes.c_void_p)
772776

777+
cfunc = lib_importer.windll.DAQmxRegisterEveryNSamplesEvent
778+
cfunc.argtypes = [
779+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
780+
ctypes.c_uint, DAQmxEveryNSamplesEventCallbackPtr, ctypes.c_void_p]
781+
773782
if callback_method is not None:
774783
callback_method_ptr = DAQmxEveryNSamplesEventCallbackPtr(
775784
callback_method)
776785
self._every_n_acquired_event_callbacks.append(
777786
callback_method_ptr)
778787
else:
779788
del self._every_n_acquired_event_callbacks[:]
780-
781-
cfunc = lib_importer.windll.DAQmxRegisterEveryNSamplesEvent
782-
cfunc.argtypes = [
783-
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
784-
ctypes.c_uint, DAQmxEveryNSamplesEventCallbackPtr, ctypes.c_void_p]
789+
callback_method_ptr = None
790+
cfunc.argtypes = [
791+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
792+
ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p]
785793

786794
error_code = cfunc(
787795
self._handle, EveryNSamplesEventType.ACQUIRED_INTO_BUFFER.value,
@@ -826,19 +834,23 @@ def register_every_n_samples_transferred_from_buffer_event(
826834
ctypes.c_int32, lib_importer.task_handle, ctypes.c_int32,
827835
ctypes.c_uint32, ctypes.c_void_p)
828836

837+
cfunc = lib_importer.windll.DAQmxRegisterEveryNSamplesEvent
838+
cfunc.argtypes = [
839+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
840+
ctypes.c_uint, DAQmxEveryNSamplesEventCallbackPtr,
841+
ctypes.c_void_p]
842+
829843
if callback_method is not None:
830844
callback_method_ptr = DAQmxEveryNSamplesEventCallbackPtr(
831845
callback_method)
832846
self._every_n_transferred_event_callbacks.append(
833847
callback_method_ptr)
834848
else:
835849
del self._every_n_transferred_event_callbacks[:]
836-
837-
cfunc = lib_importer.windll.DAQmxRegisterEveryNSamplesEvent
838-
cfunc.argtypes = [
839-
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
840-
ctypes.c_uint, DAQmxEveryNSamplesEventCallbackPtr,
841-
ctypes.c_void_p]
850+
callback_method_ptr = None
851+
cfunc.argtypes = [
852+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
853+
ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p]
842854

843855
error_code = cfunc(
844856
self._handle, EveryNSamplesEventType.TRANSFERRED_FROM_BUFFER.value,
@@ -878,16 +890,20 @@ def register_signal_event(self, signal_type, callback_method):
878890
ctypes.c_int32, lib_importer.task_handle, ctypes.c_int32,
879891
ctypes.c_void_p)
880892

893+
cfunc = lib_importer.daqlib.DAQmxRegisterSignalEvent
894+
cfunc.argtypes = [
895+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
896+
DAQmxSignalEventCallbackPtr, ctypes.c_void_p]
897+
881898
if callback_method is not None:
882899
callback_method_ptr = DAQmxSignalEventCallbackPtr(callback_method)
883900
self._signal_event_callbacks.append(callback_method_ptr)
884901
else:
885902
del self._signal_event_callbacks[:]
886-
887-
cfunc = lib_importer.daqlib.DAQmxRegisterSignalEvent
888-
cfunc.argtypes = [
889-
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
890-
DAQmxSignalEventCallbackPtr, ctypes.c_void_p]
903+
callback_method_ptr = None
904+
cfunc.argtypes = [
905+
lib_importer.task_handle, ctypes.c_int, ctypes.c_uint,
906+
ctypes.c_void_p, ctypes.c_void_p]
891907

892908
error_code = cfunc(
893909
self._handle, signal_type.value, 0, callback_method_ptr, None)

nidaqmx/tests/test_events.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import pytest
2+
import random
3+
import time
4+
5+
import nidaqmx
6+
from nidaqmx.constants import AcquisitionType
7+
from nidaqmx.tests.fixtures import x_series_device
8+
from nidaqmx.tests.helpers import generate_random_seed
9+
10+
11+
class TestEvents(object):
12+
"""
13+
Contains a collection of pytest tests that validate the NI-DAQmx events
14+
functionality in the Python NI-DAQmx API.
15+
"""
16+
17+
@pytest.mark.parametrize('seed', [generate_random_seed()])
18+
def test_every_n_samples_event(self, x_series_device, seed):
19+
# Reset the pseudorandom number generator with seed.
20+
random.seed(seed)
21+
22+
samples_chunk = 100
23+
sample_rate = 5000
24+
25+
with nidaqmx.Task() as task:
26+
task.ai_channels.add_ai_voltage_chan(
27+
x_series_device.ai_physical_chans[0].name)
28+
29+
samples_multiple = random.randint(2, 5)
30+
num_samples = samples_chunk * samples_multiple
31+
32+
task.timing.cfg_samp_clk_timing(
33+
sample_rate, sample_mode=AcquisitionType.FINITE,
34+
samps_per_chan=num_samples)
35+
36+
# Python 2.X does not have nonlocal keyword.
37+
non_local_var = {'samples_read': 0}
38+
39+
def callback(task_handle, every_n_samples_event_type,
40+
number_of_samples, callback_data):
41+
samples = task.read(
42+
number_of_samples_per_channel=samples_chunk, timeout=2.0)
43+
non_local_var['samples_read'] += len(samples)
44+
return 0
45+
46+
task.register_every_n_samples_acquired_into_buffer_event(
47+
samples_chunk, callback)
48+
49+
task.start()
50+
task.wait_until_done(timeout=2)
51+
52+
# Wait until done doesn't wait for all callbacks to be processed.
53+
time.sleep(1)
54+
task.stop()
55+
56+
assert non_local_var['samples_read'] == num_samples
57+
58+
samples_multiple = random.randint(2, 5)
59+
num_samples = samples_chunk * samples_multiple
60+
61+
task.timing.cfg_samp_clk_timing(
62+
sample_rate, sample_mode=AcquisitionType.FINITE,
63+
samps_per_chan=num_samples)
64+
65+
non_local_var = {'samples_read': 0}
66+
67+
# Unregister event callback function by passing None.
68+
task.register_every_n_samples_acquired_into_buffer_event(
69+
samples_chunk, None)
70+
71+
task.start()
72+
task.wait_until_done(timeout=2)
73+
74+
# Wait until done doesn't wait for all callbacks to be processed.
75+
time.sleep(1)
76+
task.stop()
77+
78+
assert non_local_var['samples_read'] == 0

requirements.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#
2+
# This file is autogenerated by pip-compile
3+
# To update, run:
4+
#
5+
# pip-compile --output-file requirements.txt setup.py
6+
#
7+
8+
enum34==1.1.6 ; python_version < "3.4"
9+
numpy==1.12.1
10+
six==1.10.0

requirements_dev.in

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Sphinx
2+
sphinx_rtd_theme
3+
tox

requirements_dev.txt

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# This file is autogenerated by pip-compile
3+
# To update, run:
4+
#
5+
# pip-compile --output-file requirements_dev.txt requirements_dev.in
6+
#
7+
8+
alabaster==0.7.10 # via sphinx
9+
babel==2.4.0 # via sphinx
10+
certifi==2017.4.17 # via requests
11+
chardet==3.0.3 # via requests
12+
colorama==0.3.9 # via sphinx
13+
docutils==0.13.1 # via sphinx
14+
idna==2.5 # via requests
15+
imagesize==0.7.1 # via sphinx
16+
jinja2==2.9.6 # via sphinx
17+
markupsafe==1.0 # via jinja2
18+
pluggy==0.4.0 # via tox
19+
py==1.4.34 # via tox
20+
pygments==2.2.0 # via sphinx
21+
pytz==2017.2 # via babel
22+
requests==2.17.3 # via sphinx
23+
six==1.10.0 # via sphinx
24+
snowballstemmer==1.2.1 # via sphinx
25+
sphinx-rtd-theme==0.2.4
26+
sphinx==1.6.2
27+
sphinxcontrib-websupport==1.0.1 # via sphinx
28+
tox==2.7.0
29+
typing==3.6.1 # via sphinx
30+
urllib3==1.21.1 # via requests
31+
virtualenv==15.1.0 # via tox

requirements_test.in

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest

requirements_test.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#
2+
# This file is autogenerated by pip-compile
3+
# To update, run:
4+
#
5+
# pip-compile --output-file requirements_test.txt requirements_test.in
6+
#
7+
8+
colorama==0.3.9 # via pytest
9+
py==1.4.34 # via pytest
10+
pytest==3.1.1

setup.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import os
2-
from setuptools import setup
1+
from setuptools import setup
32
from setuptools.command.test import test as TestCommand
43

54

@@ -13,14 +12,15 @@ def run_tests(self):
1312
import pytest
1413
pytest.main(self.test_args)
1514

16-
15+
1716
pypi_name = 'nidaqmx'
1817

1918

20-
def get_version():
19+
def get_version(name):
20+
import os
2121
version = None
2222
script_dir = os.path.dirname(os.path.realpath(__file__))
23-
script_dir = os.path.join(script_dir, pypi_name)
23+
script_dir = os.path.join(script_dir, name)
2424
if not os.path.exists(os.path.join(script_dir, 'VERSION')):
2525
version = '1.0.0dev0'
2626
else:
@@ -36,7 +36,7 @@ def read_contents(file_to_read):
3636

3737
setup(
3838
name=pypi_name,
39-
version=get_version(),
39+
version=get_version(pypi_name),
4040
description='NI-DAQmx Python API',
4141
long_description=read_contents('README.rst'),
4242
author='National Instruments',

tox.ini

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ envlist = py27,py34,py35,py36
1010
install_command = pip install --pre -i http://ni-pypi.amer.corp.natinst.com --trusted-host ni-pypi.amer.corp.natinst.com {opts} {packages}
1111
commands = pytest --quiet --junitxml=pytests-{envname}.xml
1212
deps =
13-
pytest
13+
-rrequirements_test.txt
14+
-rrequirements.txt

0 commit comments

Comments
 (0)