Skip to content

Commit

Permalink
Support Non-ASCII Characters for User-Provided String (#518)
Browse files Browse the repository at this point in the history
* Convert Parameter Strings to UTF-8

* update dll and decode values with utf-8

* address comments

* address comments

* fix typo

* Add automatic fallback and feature toggle

* address comments

* address comments

* remove .env temporary

* address comment

* add codegen changes

* add .env to gitignore

* minor fix

* fix indentation

* modify encoding for missing functions
  • Loading branch information
charitylxy authored Mar 4, 2024
1 parent 9648bc6 commit 981e45f
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 66 deletions.
14 changes: 14 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This is a sample nidaqmx-python configuration file.

# To use it:
# - Copy this file to your application's directory or one of its parent directories
# (such as the root of your Git repository).
# - Rename it to `.env`.
# - Uncomment and edit the options you want to change.
# - Restart any affected applications or services.

# By default, nidaqmx-python on Windows uses nicai_utf8, the UTF-8 version of the NI-DAQmx C library.
# If that is not available, it falls back to nicaiu, the MBCS (multibyte character set) version. You can override
# this behavior by uncommenting the following option:

# NIDAQMX_C_LIBRARY=nicaiu
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ test_results/
htmlcov/

# Environments
.env
.venv

# Built artifacts
Expand Down
67 changes: 52 additions & 15 deletions generated/nidaqmx/_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import platform
import sys
import threading
import locale
from decouple import config
from typing import cast, TYPE_CHECKING

from nidaqmx.errors import DaqNotFoundError, DaqNotSupportedError, DaqFunctionNotSupportedError
Expand Down Expand Up @@ -46,13 +48,13 @@ def _setter(self, val):

class CtypesByteString:
"""
Custom argtype that automatically converts unicode strings to ASCII
strings in Python 3.
Custom argtype that automatically converts unicode strings to encoding
used by the DAQmx C API DLL in Python 3.
"""
@classmethod
def from_param(cls, param):
if isinstance(param, str):
param = param.encode('ascii')
param = param.encode(lib_importer.encoding)
return ctypes.c_char_p(param)


Expand Down Expand Up @@ -128,6 +130,7 @@ def __init__(self):
self._cdll = None
self._cal_handle = None
self._task_handle = None
self._encoding = None

@property
def windll(self):
Expand All @@ -148,39 +151,73 @@ def task_handle(self) -> type:
@property
def cal_handle(self) -> type:
return CalHandle


@property
def encoding(self):
if self._encoding is None:
self._import_lib()
return self._encoding

def _import_lib(self):
"""
Determines the location of and loads the NI-DAQmx CAI DLL.
"""
self._windll = None
self._cdll = None
self._encoding = None

windll = None
cdll = None

if sys.platform.startswith('win') or sys.platform.startswith('cli'):
try:
if 'iron' in platform.python_implementation().lower():
windll = ctypes.windll.nicaiu
cdll = ctypes.cdll.nicaiu
else:
windll = ctypes.windll.LoadLibrary('nicaiu')
cdll = ctypes.cdll.LoadLibrary('nicaiu')
except (OSError, WindowsError) as e:
raise DaqNotFoundError(_DAQ_NOT_FOUND_MESSAGE) from e
encoding = None

if sys.platform.startswith('win'):

def _load_lib(libname: str):
windll = ctypes.windll.LoadLibrary(libname)
cdll = ctypes.cdll.LoadLibrary(libname)
return windll, cdll

# Feature Toggle to load nicaiu.dll or nicai_utf8.dll
# The Feature Toggle can be set in the .env file
nidaqmx_c_library = config('NIDAQMX_C_LIBRARY', default=None)

if nidaqmx_c_library is not None:
try:
if nidaqmx_c_library=="nicaiu":
windll, cdll = _load_lib("nicaiu")
encoding = locale.getlocale()[1]
elif nidaqmx_c_library=="nicai_utf8":
windll, cdll = _load_lib("nicai_utf8")
encoding = 'utf-8'
else:
raise ValueError(f"Unsupported NIDAQMX_C_LIBRARY value: {nidaqmx_c_library}")
except (OSError, WindowsError) as e:
raise DaqNotFoundError(_DAQ_NOT_FOUND_MESSAGE) from e
else:
try:
windll, cdll = _load_lib("nicai_utf8")
encoding = 'utf-8'
except (OSError, WindowsError):
# Fallback to nicaiu.dll if nicai_utf8.dll cannot be loaded
try:
windll, cdll = _load_lib("nicaiu")
encoding = locale.getlocale()[1]
except (OSError, WindowsError) as e:
raise DaqNotFoundError(_DAQ_NOT_FOUND_MESSAGE) from e
elif sys.platform.startswith('linux'):
# On linux you can use the command find_library('nidaqmx')
if find_library('nidaqmx') is not None:
cdll = ctypes.cdll.LoadLibrary(find_library('nidaqmx'))
windll = cdll
encoding = locale.getlocale()[1]
else:
raise DaqNotFoundError(_DAQ_NOT_FOUND_MESSAGE)
else:
raise DaqNotSupportedError(_DAQ_NOT_SUPPORTED_MESSAGE.format(sys.platform))

self._windll = DaqFunctionImporter(windll)
self._cdll = DaqFunctionImporter(cdll)
self._encoding = encoding


lib_importer = DaqLibImporter()
Loading

0 comments on commit 981e45f

Please sign in to comment.