Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pyvdr for openSUSE:Factory 
checked in at 2021-03-18 22:55:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyvdr (Old)
 and      /work/SRC/openSUSE:Factory/.python-pyvdr.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pyvdr"

Thu Mar 18 22:55:10 2021 rev:5 rq:879833 version:0.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyvdr/python-pyvdr.changes        
2020-07-31 15:59:38.792493506 +0200
+++ /work/SRC/openSUSE:Factory/.python-pyvdr.new.2401/python-pyvdr.changes      
2021-03-18 22:55:12.679548388 +0100
@@ -1,0 +2,9 @@
+Thu Mar 18 07:24:38 UTC 2021 - Martin Hauke <[email protected]>
+
+- Update to version 0.3.0
+  * refactored svdrp socket handling.
+  * changed behaviour of get_channel_epg_info which now expects
+    the channel no as parameter instead of getting the channel
+    itself.
+
+-------------------------------------------------------------------

Old:
----
  pyvdr-0.2.3.tar.gz

New:
----
  pyvdr-0.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pyvdr.spec ++++++
--- /var/tmp/diff_new_pack.ORJn3d/_old  2021-03-18 22:55:14.751550626 +0100
+++ /var/tmp/diff_new_pack.ORJn3d/_new  2021-03-18 22:55:14.755550630 +0100
@@ -1,8 +1,8 @@
 #
 # spec file for package python-pyvdr
 #
-# Copyright (c) 2020 SUSE LLC
-# Copyright (c) 2020, Martin Hauke <[email protected]>
+# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2020-2021, Martin Hauke <[email protected]>
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-pyvdr
-Version:        0.2.3
+Version:        0.3.0
 Release:        0
 Summary:        Python library for accessing a Linux VDR via SVDRP
 License:        MIT

++++++ pyvdr-0.2.3.tar.gz -> pyvdr-0.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyvdr-0.2.3/pyvdr/pyvdr.py 
new/pyvdr-0.3.0/pyvdr/pyvdr.py
--- old/pyvdr-0.2.3/pyvdr/pyvdr.py      2020-07-29 23:00:01.000000000 +0200
+++ new/pyvdr-0.3.0/pyvdr/pyvdr.py      2021-03-17 18:01:00.000000000 +0100
@@ -1,21 +1,20 @@
 #!/usr/bin/env python3
 
 from .svdrp import SVDRP
+from .svdrp import SVDRP_COMMANDS
+from .svdrp import SVDRP_RESULT_CODE
+
 import logging
 import re
 from collections import namedtuple
 
-EPG_DATA_RECORD = '215'
 epg_info = namedtuple('EPGDATA', 'Channel Title Description')
-# timer_info = namedtuple('TIMER', 'Status Name Date Description')
-# channel_info = namedtuple('CHANNEL', 'Number Name')
 
 FLAG_TIMER_ACTIVE = 1
 FLAG_TIMER_INSTANT_RECORDING = 2
 FLAG_TIMER_VPS = 4
 FLAG_TIMER_RECORDING = 8
 
-
 _LOGGER = logging.getLogger(__name__)
 
 
@@ -26,12 +25,8 @@
         self.svdrp = SVDRP(hostname=self.hostname, timeout=timeout)
         self.timers = None
 
-    def sensors(self):
-        return ['Vdrinfo']
-
     def stat(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("STAT DISK")
+        self.svdrp.send_cmd(SVDRP_COMMANDS.DISK_INFO)
         disk_stat_response = self.svdrp.get_response()[1:][0]
 
         if disk_stat_response.Code != SVDRP.SVDRP_STATUS_OK:
@@ -40,7 +35,6 @@
         disk_stat_parts = re.match(
             r'(\d*)\w. (\d*)\w. (\d*)',
             disk_stat_response.Value, re.M | re.I)
-        self.svdrp.disconnect()
         if disk_stat_parts:
             return [disk_stat_parts.group(1),
                     disk_stat_parts.group(2),
@@ -48,19 +42,24 @@
         else:
             return None
 
+    """
+    Gets the channel info and returns the channel number and the channel name.
+    """
     def get_channel(self):
-        self.svdrp.connect()
-        if not self.svdrp.is_connected():
+        self.svdrp.send_cmd(SVDRP_COMMANDS.GET_CHANNEL)
+        responses = self.svdrp.get_response()
+        _LOGGER.debug("Response of get channel cmd: '%s'" % responses)
+        if len(responses) < 1:
             return None
-
-        self.svdrp.send_cmd("CHAN")
-        generic_response = self.svdrp.get_response()[-1]
+        # get 2nd element (1. welcome, 2. response, 3. quit msg)
+        generic_response = responses[-2]
         channel = self._parse_channel_response(generic_response)
-        self.svdrp.disconnect()
+        _LOGGER.debug("Returned Chan: '%s'" % channel)
         return channel
 
     @staticmethod
     def _parse_channel_response(channel_data):
+        _LOGGER.debug("Parsing Channel response to fields: %s" % 
channel_data.Value)
         channel_info = {}
 
         channel_parts = re.match(
@@ -75,16 +74,16 @@
     @staticmethod
     def _parse_timer_response(response):
         timer = {}
-        m = re.match(
+        timer_match = re.match(
             r'^(\d) 
(\d{1,2}):(\d{1,2}):(\d{4}-\d{2}-\d{2}):(\d{4}):(\d{4}):(\d+):(\d+):(.*):(.*)$',
             response.Value,
             re.M | re.I)
 
-        if m:
-            timer['status'] = m.group(2)
-            timer['channel'] = m.group(3)
-            timer['date'] = m.group(4)
-            timer['name'] = m.group(9)
+        if timer_match:
+            timer['status'] = timer_match.group(2)
+            timer['channel'] = timer_match.group(3)
+            timer['date'] = timer_match.group(4)
+            timer['name'] = timer_match.group(9)
             timer['description'] = ""
             timer['series'] = timer['name'].find('~') != -1
             timer['instant'] = False
@@ -96,28 +95,21 @@
 
     def get_timers(self):
         timers = []
-        self.svdrp.connect()
-        self.svdrp.send_cmd("LSTT")
+        self.svdrp.send_cmd(SVDRP_COMMANDS.LIST_TIMERS)
         responses = self.svdrp.get_response()
-        self.svdrp.disconnect()
         for response in responses:
-            if response.Code != '250':
+            if response.Code != SVDRP_RESULT_CODE.SUCCESS:
                 continue
             timers.append(self._parse_timer_response(response))
         return timers
 
     def is_recording(self):
-        self.svdrp.connect()
-        if not self.svdrp.is_connected():
-            return None
-
-        self.svdrp.send_cmd("LSTT")
+        self.svdrp.send_cmd(SVDRP_COMMANDS.LIST_TIMERS)
         responses = self.svdrp.get_response()
         for response in responses:
-            if response.Code != '250':
+            if response.Code != SVDRP_RESULT_CODE.SUCCESS:
                 continue
             timer = self._parse_timer_response(response)
-            self.svdrp.disconnect()
             if len(timer) <= 0:
                 _LOGGER.debug("No output from timer parsing.")
                 return None
@@ -129,17 +121,13 @@
 
         return None
 
-    def get_channel_epg_info(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("CHAN")
-        chan = self.svdrp.get_response()[-1]
-        channel = self._parse_channel_response(chan)
-        self.svdrp.send_cmd("LSTE {} now".format(channel['number']))
+    def get_channel_epg_info(self, channel_no=1):
+        epg_title = epg_channel = epg_description = None
+        self.svdrp.send_cmd(f"{SVDRP_COMMANDS.LIST_EPG} {channel_no} now")
         epg_data = self.svdrp.get_response()[1:]
-        self.svdrp.disconnect()
-        for d in epg_data:
-            if d[0] == EPG_DATA_RECORD:
-                epg = re.match(r'^(\S)\s(.*)$', d[2], re.M | re.I)
+        for data in epg_data:
+            if data[0] == SVDRP_RESULT_CODE.EPG_DATA_RECORD:
+                epg = re.match(r'^(\S)\s(.*)$', data[2], re.M | re.I)
                 if epg is not None:
                     epg_field_type = epg.group(1)
                     epg_field_value = epg.group(2)
@@ -151,28 +139,23 @@
                     if epg_field_type == 'D':
                         epg_description = epg_field_value
 
-        return channel, epg_info(
+        return epg_info(
             Channel=epg_channel,
             Title=epg_title,
             Description=epg_description)
 
     def channel_up(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("CHAN +")
-        reponse_text = self.svdrp.get_response_as_text()
-        self.svdrp.disconnect()
-        return reponse_text
+        self.svdrp.send_cmd(SVDRP_COMMANDS.CHANNEL_UP)
+        response_text = self.svdrp.get_response_as_text()
+        return response_text
 
     def channel_down(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("CHAN -")
-        reponse_text = self.svdrp.get_response_as_text()
-        self.svdrp.disconnect()
-        return reponse_text
+        self.svdrp.send_cmd(SVDRP_COMMANDS.CHANNEL_DOWN)
+        response_text = self.svdrp.get_response_as_text()
+        return response_text
 
     def list_recordings(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("LSTR")
+        self.svdrp.send_cmd(SVDRP_COMMANDS.LIST_RECORDINGS)
         return self.svdrp.get_response()[1:]
 
     @staticmethod
@@ -181,14 +164,3 @@
         if isinstance(timer_status, str):
             return int(timer_status) & flag
         return timer_status & flag
-
-    def test(self):
-        self.svdrp.connect()
-        self.svdrp.send_cmd("LSTE 6 now")
-        return self.svdrp.get_response_text()
-
-    def finish(self):
-        self.svdrp.shutdown()
-
-    def mypyvdr(self):
-        return (u'blubb')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyvdr-0.2.3/pyvdr/svdrp.py 
new/pyvdr-0.3.0/pyvdr/svdrp.py
--- old/pyvdr-0.2.3/pyvdr/svdrp.py      2020-07-29 23:00:01.000000000 +0200
+++ new/pyvdr-0.3.0/pyvdr/svdrp.py      2021-03-17 18:01:00.000000000 +0100
@@ -1,16 +1,35 @@
 #!/usr/bin/env python3
 
+from enum import Enum
 import re
 import socket
 import logging
 from collections import namedtuple
 
+
+SVDRP_CMD_LF = '\r\n'
 response_data = namedtuple('ResponseData', 'Code Separator Value')
 SVDRP_EMPTY_RESPONSE = ""
 
 _LOGGER = logging.getLogger(__name__)
 
 
+class SVDRP_COMMANDS(str, Enum):
+    QUIT = 'quit'
+    LIST_TIMERS = "LSTT"
+    GET_CHANNEL = "CHAN"
+    DISK_INFO = "STAT DISK"
+    LIST_RECORDINGS = "LSTR"
+    LIST_EPG = "LSTE"
+    CHANNEL_UP = "CHAN +"
+    CHANNEL_DOWN = "CHAN -"
+
+
+class SVDRP_RESULT_CODE(str, Enum):
+    SUCCESS = '250'
+    EPG_DATA_RECORD = '215'
+
+
 class SVDRP(object):
     SVDRP_STATUS_OK = '250'
 
@@ -19,60 +38,75 @@
         self.port = port
         self.timeout = timeout
         self.socket = None
-        self.socket_file = None
         self.responses = []
 
-    def connect(self):
+    def _connect(self):
         if self.socket is None:
             try:
                 _LOGGER.debug("Setting up connection to 
{}".format(self.hostname))
                 self.socket = socket.create_connection((self.hostname, 
self.port), timeout=self.timeout)
-                self.socket_file = self.socket.makefile('r')
+                self.responses = []
             except socket.error as se:
                 _LOGGER.info('Unable to connect. Not powered on? 
{}'.format(se))
 
-    def is_connected(self):
-        return self.socket is not None
-
-    def disconnect(self):
+    def _disconnect(self, send_quit=False):
         _LOGGER.debug("Closing communication with server.")
         if self.socket is not None:
-            self.send_cmd("quit")
-            self.socket_file.close()
+            if send_quit:
+                
self.socket.sendall(SVDRP_COMMANDS.QUIT.join(SVDRP_CMD_LF).encode())
             self.socket.close()
+            self.socket = None
 
-        self.responses = []
-        self.socket = None
+    def is_connected(self):
+        return self.socket is not None
 
+    """
+    Sends a SVDRP command to the VDR instance, by default the connection will 
be created and also be closed at the end.
+    If the connection should be kept open in the end (e.g. for sending 
multi-commands)
+    the param auto_disconnect needs to be set to False on invoking.
+    The result will be stored in the internal responses array for later 
content handling.
+    :return void / nothing
+    """
     def send_cmd(self, cmd):
-        _LOGGER.debug("Send cmd: {}".format(cmd))
-        if not self.is_connected():
-            return
+        self._connect()
 
-        cmd += '\r\n'
-
-        if isinstance(cmd, str):
-            cmd = cmd.encode("utf-8")
+        command_list = [cmd]
+        command_list.extend([SVDRP_COMMANDS.QUIT])
+        _LOGGER.debug("Send commands: {}".format(command_list))
 
         try:
-            self.socket.sendall(cmd)
+            data = list()
+            [self.socket.sendall(s.join(SVDRP_CMD_LF).encode()) for s in 
command_list]
+            while True:
+                data.append(self.socket.recv(16))
+                if not data[-1]:
+                    break
         except IOError as e:
             _LOGGER.debug("IOError e {}, closing connection".format(e))
-            self.socket.close()
+        finally:
+            _LOGGER.debug('Decoding data into responses: %s' % data)
+            response_raw = b''.join(data)
+            [self.responses.append(self._parse_response_item(s.decode())) for 
s in response_raw.splitlines()]
 
-    def _parse_response(self, resp):
+            self._disconnect()
+    """
+    Parses a single response item into data set
+    :return response_data object
+    """
+    def _parse_response_item(self, resp):
         # <Reply code:3><-|Space><Text><Newline>
-        matchobj = re.match(r'^(\d{3})(.)(.*)', resp, re.M | re.I)
+        match_obj = re.match(r'^(\d{3})(.)(.*)', resp, re.M | re.I)
 
-        return response_data(Code=matchobj.group(1), 
Separator=matchobj.group(2), Value=matchobj.group(3))
+        return response_data(Code=match_obj.group(1), 
Separator=match_obj.group(2), Value=match_obj.group(3))
 
     """
     Gets the response from the last CMD and puts it in the internal list.
     :return Namedtuple (Code, Separator, Value)
     """
-    def _read_response(self):
-        for line in self.socket_file:
-            response_entry = self._parse_response(line)
+    def _read_response_(self):
+
+        for line in self.responses:
+            response_entry = self._parse_response_item(line)
             self.responses.append(response_entry)
 
             # The first and last row are separated simply by ' ', other with 
'-'.
@@ -85,7 +119,6 @@
     :return response as plain text
     """
     def get_response_as_text(self):
-        self._read_response()
         return "".join(str(self.responses))
 
     """
@@ -95,20 +128,12 @@
     :return List of Namedtuple (Code, Separator, Value)
     """
     def get_response(self, single_line=False):
-        if not self.is_connected():
+        if len(self.responses) == 0:
             return SVDRP_EMPTY_RESPONSE
 
-        self._read_response()
         if single_line:
             _LOGGER.debug("Returning single item")
             return self.responses[2]
         else:
             _LOGGER.debug("Returning {} items".format(len(self.responses)))
             return self.responses
-
-    def shutdown(self):
-        if self.socket is not None:
-            self.send_cmd("quit")
-            self.socket_file.close()
-            self.socket.close()
-            self.responses = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyvdr-0.2.3/setup.py new/pyvdr-0.3.0/setup.py
--- old/pyvdr-0.2.3/setup.py    2020-07-29 23:00:01.000000000 +0200
+++ new/pyvdr-0.3.0/setup.py    2021-03-17 18:01:00.000000000 +0100
@@ -4,7 +4,7 @@
     long_description = fh.read()
 
 setup(name='pyvdr',
-      version='0.2.3',
+      version='0.3.0',
       description='Python library for accessing a Linux VDR via SVDRP',
       long_description=long_description,
       long_description_content_type="text/markdown",
@@ -15,4 +15,4 @@
       packages=['pyvdr'],
       zip_safe=False,
       python_requires='>=3.6',
-)
+     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyvdr-0.2.3/test/test_PYVDR.py 
new/pyvdr-0.3.0/test/test_PYVDR.py
--- old/pyvdr-0.2.3/test/test_PYVDR.py  2020-07-29 23:00:01.000000000 +0200
+++ new/pyvdr-0.3.0/test/test_PYVDR.py  2021-03-17 18:01:00.000000000 +0100
@@ -15,11 +15,11 @@
         )
 
     def test__parse_channel_response(self):
-        chan_ard = self.func._parse_channel_response(["", "", "1 ARD"])
+        chan_ard = self.func._parse_channel_response(response_data("", "", "1 
ARD"))
         self.assertEqual(chan_ard['number'], "1")
         self.assertEqual(chan_ard['name'], "ARD")
 
-        chan_prosieben = self.func._parse_channel_response(["", "", "11 Pro 
Sieben"])
+        chan_prosieben = self.func._parse_channel_response(response_data("", 
"", "11 Pro Sieben"))
         self.assertEqual(chan_prosieben['number'], "11")
         self.assertEqual(chan_prosieben['name'], "Pro Sieben")
 
@@ -58,17 +58,44 @@
             })
 
         # timer active, not yet recording
-        self.assertTrue(self.func._check_timer_recording_flag(t_active, 
pyvdr.FLAG_TIMER_ACTIVE), "Timer should be active")
-        self.assertFalse(self.func._check_timer_recording_flag(t_active, 
pyvdr.FLAG_TIMER_RECORDING), "Timer should not be recording")
+        self.assertTrue(
+            self.func._check_timer_recording_flag(
+                t_active,
+                pyvdr.FLAG_TIMER_ACTIVE
+            ), "Timer should be active")
+        self.assertFalse(
+            self.func._check_timer_recording_flag(
+                t_active,
+                pyvdr.FLAG_TIMER_RECORDING
+            ), "Timer should not be recording")
 
         # timer active, recording
-        
self.assertTrue(self.func._check_timer_recording_flag(t_active_and_recording, 
pyvdr.FLAG_TIMER_ACTIVE), "Timer should be active")
-        
self.assertTrue(self.func._check_timer_recording_flag(t_active_and_recording, 
pyvdr.FLAG_TIMER_RECORDING), "Timer should be recording")
+        self.assertTrue(
+            self.func._check_timer_recording_flag(
+                t_active_and_recording,
+                pyvdr.FLAG_TIMER_ACTIVE
+            ), "Timer should be active")
+        self.assertTrue(
+            self.func._check_timer_recording_flag(
+                t_active_and_recording,
+                pyvdr.FLAG_TIMER_RECORDING
+            ), "Timer should be recording")
 
         # instant recording
-        
self.assertTrue(self.func._check_timer_recording_flag(t_active_and_instant_recording,
 pyvdr.FLAG_TIMER_RECORDING), "Timer active")
-        
self.assertTrue(self.func._check_timer_recording_flag(t_active_and_instant_recording,
 pyvdr.FLAG_TIMER_RECORDING), "Timer recording")
-        
self.assertTrue(self.func._check_timer_recording_flag(t_active_and_instant_recording,
 pyvdr.FLAG_TIMER_INSTANT_RECORDING), "Timer instant recording")
+        self.assertTrue(
+            self.func._check_timer_recording_flag(
+                t_active_and_instant_recording,
+                pyvdr.FLAG_TIMER_RECORDING
+            ), "Timer active")
+        self.assertTrue(
+        self.func._check_timer_recording_flag(
+            t_active_and_instant_recording,
+            pyvdr.FLAG_TIMER_RECORDING
+        ), "Timer recording")
+        self.assertTrue(
+            self.func._check_timer_recording_flag(
+                t_active_and_instant_recording, 
pyvdr.FLAG_TIMER_INSTANT_RECORDING
+        ), "Timer instant recording")
 
     def test__parse_timer_responses(self):
         parseable_responses = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyvdr-0.2.3/test/test_Real.py 
new/pyvdr-0.3.0/test/test_Real.py
--- old/pyvdr-0.2.3/test/test_Real.py   1970-01-01 01:00:00.000000000 +0100
+++ new/pyvdr-0.3.0/test/test_Real.py   2021-03-17 18:01:00.000000000 +0100
@@ -0,0 +1,18 @@
+import unittest
+from pyvdr import PYVDR
+
+class MyTestCase(unittest.TestCase):
+    def test_something(self):
+
+        # pyvdr = PYVDR(hostname='easyvdr.fritz.box')
+        # channel = pyvdr.get_channel()
+        # epg_info = pyvdr.get_channel_epg_info()
+        # diskstat = pyvdr.stat()
+        # list_of_timers = pyvdr.get_timers()
+        # is_recording = pyvdr.is_recording()
+        # list_of_recordings = pyvdr.list_recordings()
+
+        pass
+
+if __name__ == '__main__':
+    unittest.main()

Reply via email to