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

NTNDArray post() method does not check if what is passed in is a Value #146

Open
sfeister opened this issue Jul 27, 2024 · 3 comments
Open

Comments

@sfeister
Copy link

The NTScalar class method wrap() method begins with:

    def wrap(self, value, **kws):
        ....
        if isinstance(value, Value):
            pass

However, the NTNDArray method is missing this pass statement. Because of this, the example in the documentation about modifying a Value before posting it doesn't work for NTNDArrays, which is too bad as I'd like to be able to set the fields "uniqueId" and "dataTimeStamp" myself.

I've made a workaround by creating a subclass of NTNDArray and writing my own wrap method, but I thought I'd bring it to your attention!

In case anyone is looking for a workaround, here's one example:

import numpy as np
from p4p import Value
from p4p.nt import NTNDArray
from p4p.server.thread import SharedPV

class ModifiedNTNDArray(NTNDArray):
    """ Modified to allow for more customization """
    def wrap(self, value, **kws):
        if isinstance(value, Value):
            return value
        else:
            return super().wrap(value, **kws)
        
if __name__ == "__main__": 
    pv = SharedPV(nt=ModifiedNTNDArray(), initial=np.zeros(500))
    assert pv.current().raw['uniqueId'] == 0


    val = pv._wrap(np.ones(500))
    val['uniqueId'] = 23
    pv.post(val)
    assert pv.current().raw['uniqueId'] == 23
@sfeister
Copy link
Author

sfeister commented Jul 27, 2024

It might also be nice also to put the optional keywords "uniqueId" and "dataTimeStamp" in the wrap method as optional keywords, like I did in this second example modification to the NTNDArray class:

import time
from datetime import datetime
import numpy as np

from p4p import Value
from p4p.nt import NTScalar, NTNDArray
from p4p.server.thread import SharedPV

class ModifiedNTNDArray(NTNDArray):
    """ Modified to allow for uniqueId to be set as a keyword"""
    def wrap(self, value, uniqueId=0, dataTimeStamp=None, **kws):
        if isinstance(value, Value):
            return self._annotate(value, **kws)
        
        else:
            value = super().wrap(value, **kws)
            value['uniqueId'] = uniqueId
            
            if dataTimeStamp is not None: # this code section is copied from the NTBase class
                # dataTimeStamp may be: datetime, seconds as float or int, or tuple of (sec, ns)
                if isinstance(dataTimeStamp, datetime):
                    dataTimeStamp = datetime.timestamp(dataTimeStamp)

                if isinstance(dataTimeStamp, (int, float)):
                    sec, ns = divmod(dataTimeStamp, 1.0)
                    dataTimeStamp = (int(sec), int(ns*1e9))

                # at this point timestamp must be a tuple of (sec, ns)
                value['dataTimeStamp'] = {'secondsPastEpoch':dataTimeStamp[0], 'nanoseconds':dataTimeStamp[1]}
            
            return value

if __name__ == "__main__": 
    pv = SharedPV(nt=ModifiedNTNDArray(), initial=np.zeros(500))
    assert pv.current().raw['uniqueId'] == 0

    pv.post(np.ones(500), uniqueId=23, dataTimeStamp=time.time(), timestamp=time.time())
    assert pv.current().raw['uniqueId'] == 23

@mdavidsaver
Copy link
Member

However, the NTNDArray method is missing this pass statement. ...

This seems a reasonable change to me. Would you like to create a PR?

... nice also to put the optional keywords "uniqueId" and "dataTimeStamp" ...

While I have never been sure of the distinction between timeStamp and dataTimeStamp, I also don't have an objection.

Any opinions from someone who uses AD regularly?

@sfeister
Copy link
Author

sfeister commented Aug 9, 2024

@mdavidsaver I will create a PR, thanks!

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

No branches or pull requests

2 participants