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

[Prototype] Address Event Callbacks Contain Unusable Parameters Issue #472

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

DeborahOoi96
Copy link
Collaborator

@DeborahOoi96 DeborahOoi96 commented Jan 19, 2024

Attempt to address the issue brought up in #143
Made a wrapper in task.py that takes in the callback_function that doesn't have task_handle or callback_data inside, and pass it to wrappers that modify the function to add in the missing functions respectively. This is just a first pass, let me know if you have different thoughts on how to implement this.

Updated functional test to test for the cases when the callback function has missing parameters.

Why should this Pull Request be merged?

Addresses the issue brought up in #143

What testing has been done?

Functional test coverage added and all pass
image

@DeborahOoi96 DeborahOoi96 changed the title Address Event Callbacks Contain Unusable Parameters Issue [Prototype] Address Event Callbacks Contain Unusable Parameters Issue Jan 19, 2024
@DeborahOoi96
Copy link
Collaborator Author

Run lint command to pass ci build

Copy link
Collaborator

@zhindes zhindes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really not in the loop on this one. My gut says this looks kind of complicated, but maybe that's necessary. I'm gonna let Brad handle this one for now.

generated/nidaqmx/task.py Show resolved Hide resolved
@@ -760,6 +760,46 @@ def read(self, number_of_samples_per_channel=NUM_SAMPLES_UNSET,

return data.tolist()

def add_arguments_if_necessary(self, callback_function, expected_number_of_arguments):
if (callback_function.__code__.co_argcount < expected_number_of_arguments):
Copy link
Collaborator

@bkeryan bkeryan Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__code__ is a CPython implementation detail and probably won't work with PyPy.

Using the inspect module is probably more portable.

def add_arguments_if_necessary(self, callback_function, expected_number_of_arguments):
if (callback_function.__code__.co_argcount < expected_number_of_arguments):
print("Not enough arguments! Adding arguments")
if ("every_n_samples_event_type" in parameters):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[style] If-statements in Python do not have parens unless they are needed for grouping or splitting across multiple lines. Running poetry run ni-python-styleguide fix will probably fix this.

generated/nidaqmx/task.py Show resolved Hide resolved
result = lambda task_handle, signal_type, callback_data: callback_function(signal_type)
elif ("task_handle" not in parameters):
result = lambda task_handle, signal_type, callback_data: callback_function(signal_type, callback_data)
elif ("callback_data" not in parameters):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last parameter would be useful if the user was allowed to pass in an optional Python object.

Copy link
Collaborator

@bkeryan bkeryan Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example of what I mean:

def register_done_event(self, callback_method, callback_data = None):
   ...
def on_done(task, data):
    data.signal()

done_event = threading.Event()
task.register_done_event(on_done, done_event)

It's not critical because Python makes it easy to bind a closure or to pass in a member function as the callback, but it's a potential nice-to-have and it would avoid removing parameters from the signature.

print("Not enough arguments! Adding arguments")
if ("every_n_samples_event_type" in parameters):
result = self.n_samples_event_wrapper(parameters, callback_function)
elif ("signal_type" in parameters):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every N and signal events pass the callback an enum, but they use a bare ctypes or int type rather than the enum classes from nidaqmx.constants. See my prototype: https://github.com/ni/nidaqmx-python/pull/474/files

callback_method(self, EveryNSamplesEventType(every_n_samples_event_type), number_of_samples)

callback_method(self, Signal(signal_type))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants