Python wrapper

Development forum for the Python programming language.

Python wrapper

Postby esdalmaijer » 01 Jul 2014, 02:33

Hi guys,

https://github.com/esdalmaijer/PyTribe is a first attempt at creating a decent Python wrapper. The current classes are for simple communication with the eye tracker by using methods, which saves you from continuously having to send and parse JSON messages.

I plan to write an EyeTribe class on top of this soon, with higher level methods (e.g. 'calibrate', 'validate', 'drift_check', 'start_recording', 'stop_recording' etc., much like these: https://github.com/esdalmaijer/PyGaze/t ... eyetracker). But please do have a go at testing the current classes; any feedback is welcome!

Best,
Edwin
esdalmaijer
 
Posts: 5
Joined: 24 Mar 2014, 22:05

Re: Python wrapper

Postby MSchulte » 04 Jul 2014, 14:11

Looks quite nice!

I've been working on something similar, though I have been focusing more on getting the specific things I need for my project working and not on creating a complete wrapper like you have. I did things a bit differently--I created classes HeartThread and ListenerThread, for example, instead of functions that need to be called as the target of a thread.

I've been sort of hacking this code together with no regard for style guidelines, but in the next few weeks I intend to clean it up and post it here.

In the mean time, I'm curious--why don't you use the json.dumps function in your connection.create_json method? I have this function, for example:

Code: Select all
def send_message(self, category, request=None, values=None):
    '''returns the reply in a dict'''
       
    to_send = {}
    to_send[u'category'] = category
    if request is not None:
        to_send[u'request'] = request
    if values is not None:
        to_send[u'values'] = values
    to_send = json.dumps(to_send)
    with self.lock:
        self.socket.send(to_send)
        reply = self.socket.recv(BUFSIZE)
    return json.loads(reply)


I'm also using a threading.Lock() object, which is self.lock in the code above, for thread safety. I kept receiving heartbeat replies when I was trying to retrieve frame data before I added that. here's my HeartThread class (excuse the lack of documentation--will add it soon):

Code: Select all
class HeartThread(threading.Thread):
   
   
    def __init__(self, et_socket, socket_lock):
        super(HeartThread, self).__init__()
        self._stop = threading.Event()
        self.socket = et_socket
        self.lock = socket_lock
       
    def stop(self):
        self._stop.set()
       
    def run(self, interval=0.250):
        while not self._stop.is_set():
            with self.lock:
                self.socket.send('{"category":"heartbeat"}')
                logging.debug('Heartbeat reply: {}'.format(self.socket.recv(BUFSIZE)))
            sleep(interval)

# example call
heart_thr = HeartThread(self.socket, self.lock)
heart_thr.run()
MSchulte
 
Posts: 5
Joined: 10 Feb 2014, 18:13

Re: Python wrapper

Postby esdalmaijer » 28 Jul 2014, 21:16

That's a very good question, and your solution seems more elegant. It's pretty much the result of building on a proof-of-principle script; there was no real design choice behind it.

On the Lock: this is something that I still need to implement, but purely due to the hypothetical possibility of receiving the wrong kind of response. I haven't actually had problems with this yet, presumably due to a lower heartbeat frequency.

Thanks for the suggestions!

EDIT (30-Jul-2014): added the suggested Threading Lock yesterday. Immediately noticed the need for one, as it started raining replies to different commands (currently working on a command-reply matching strategy). Thanks again!
esdalmaijer
 
Posts: 5
Joined: 24 Mar 2014, 22:05

Re: Python wrapper

Postby MSchulte » 05 Aug 2014, 10:46

I actually changed the way I was doing things to make use of python's new-style classes and property decorators, which turned out to be quite handy. I also implemented a different way of dealing with command-reply matching: a custom Queue object. It inherits from Queue.LifoQueue, overrides the get() method to return an error, and adds a get_item() method that searches through the Queue and returns an item matching your request (and values if you pass those in as an argument, to distinguish between multiple request: get and request: set commands).

I'm not sure that I really NEED the lock anymore because of the changes I have made. I only have one thread ever recv-ing from the socket, but multiple functions that could send. It depends on if socket.send is inherently thread-safe, and I'm not prepared to assume that, so I am leaving in the lock for now.

I'll post my whole wrapper some time before next Wednesday :).

Cheers,
Daniel Smedema

p.s. MSchulte is actually my boss, if anyone is curious why my name and username are so different.
MSchulte
 
Posts: 5
Joined: 10 Feb 2014, 18:13

Re: Python wrapper

Postby esdalmaijer » 12 Aug 2014, 01:56

Thanks for the very good input on the response handling! I've used the tips in the newest version of my wrapper (can be found here: https://github.com/esdalmaijer/PyTribe), which is now integrated in PyGaze (https://github.com/esdalmaijer/PyGaze, see for the specific module: https://github.com/esdalmaijer/PyGaze/blob/master/pygaze/_eyetracker/libeyetribe.py).

Cheers!
Edwin
esdalmaijer
 
Posts: 5
Joined: 24 Mar 2014, 22:05


Return to Python



cron