Python API: Preparation for RPM/DEB packaging.

Recheck.

Repackage the Python API binding to include all
necessary modules in a single Python package.

Change-Id: I5e35141d413bfb1aad650217e1ca07d85646c349
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/vpp-api/python/Makefile.am b/vpp-api/python/Makefile.am
index eb58933..59b1b92 100644
--- a/vpp-api/python/Makefile.am
+++ b/vpp-api/python/Makefile.am
@@ -25,42 +25,41 @@
 #
 # Python / C extension
 #
-lib_LTLIBRARIES += vpp_api.la
-vpp_api_la_SOURCES = pneum/pneum.c vpp_papi/pneum_wrap.c
-vpp_api_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
-vpp_api_la_LDFLAGS = -module $(shell python-config --ldflags)
-vpp_api_la_CPPFLAGS = $(shell python-config --includes)
-
-# Kept around for setuptools based install.
 lib_LTLIBRARIES += libpneum.la
-libpneum_la_SOURCES = pneum/pneum.c setup.py
-libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
+libpneum_la_SOURCES = pneum/pneum.c
+libpneum_la_LIBADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread \
+                     -lm -lrt
 libpneum_la_LDFLAGS = -module
 libpneum_la_CPPFLAGS =
 
 #
 # Core VPP API
 #
-BUILT_SOURCES +=					\
-	$(prefix)/../vpp/vpp-api/vpe.py			\
-	$(prefix)/../vlib-api/vlibmemory/memclnt.py
-
-%.py: %.api
+$(srcdir)/vpp_papi/vpe.py: $(prefix)/../vpp/vpp-api/vpe.api
 	$(info Creating Python binding for $@)
 	$(CC) $(CPPFLAGS) -E -P -C -x c $<	\
 	| vppapigen --input - --python -	\
-	| pyvppapigen.py --input - > $@
+	| pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@)
 
-#
+$(srcdir)/vpp_papi/memclnt.py: $(prefix)/../vlib-api/vlibmemory/memclnt.api
+	$(info Creating Python binding for $@)
+	$(CC) $(CPPFLAGS) -E -P -C -x c $<	\
+	| vppapigen --input - --python -	\
+	| pyvppapigen.py --input - > $(srcdir)/vpp_papi/$(notdir $@)
+
 # TODO: Support both Python 2 and 3.
-install-exec-local:
-	cd $(srcdir); \
-	mkdir -p $(prefix)/lib/python2.7/site-packages; \
-	PYTHONUSERBASE=$(prefix) python setup.py install --user
+install-exec-local: $(srcdir)/vpp_papi/vpe.py $(srcdir)/vpp_papi/memclnt.py
+	cd $(srcdir);							\
+	mkdir -p $(prefix)/lib/python2.7/site-packages; 		\
+	PYTHONUSERBASE=$(prefix)					\
+	python setup.py build_ext -L $(prefix)/lib64 install --user
 
 #
 # Test client
 #
 noinst_PROGRAMS += test_pneum
 test_pneum_SOURCES = pneum/pneum.c pneum/test_pneum.c
-test_pneum_LDADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread -lm -lrt
+test_pneum_LDADD = -lvlibmemoryclient -lvlibapi -lsvm -lvppinfra -lpthread \
+                   -lm -lrt
+
+
diff --git a/vpp-api/python/pneum/pneum.c b/vpp-api/python/pneum/pneum.c
index 2637d43..7250cf6 100644
--- a/vpp-api/python/pneum/pneum.c
+++ b/vpp-api/python/pneum/pneum.c
@@ -150,8 +150,6 @@
   api_main_t *am = &api_main;
   pneum_main_t *pm = &pneum_main;
 
-  fformat (stdout,"disconnecting from vpe \n");
-
   if (pm->rx_thread_jmpbuf_valid) {
     vl_api_rx_thread_exit_t *ep;
     uword junk;
diff --git a/vpp-api/python/setup.cfg b/vpp-api/python/setup.cfg
index 5e19e8c..d645be7 100644
--- a/vpp-api/python/setup.cfg
+++ b/vpp-api/python/setup.cfg
@@ -3,5 +3,3 @@
 # 3. If at all possible, it is good practice to do this. If you cannot, you
 # will need to generate wheels for each Python version that you support.
 universal=0
-
-
diff --git a/vpp-api/python/setup.py b/vpp-api/python/setup.py
index e369a0c..a2eeff3 100644
--- a/vpp-api/python/setup.py
+++ b/vpp-api/python/setup.py
@@ -1,16 +1,34 @@
+#
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 try:
-    from setuptools import setup
+    from setuptools import setup, command, Extension
 except ImportError:
     from distutils.core import setup
 
 setup (name = 'vpp_papi',
-       version = '1.1',
+       version = '1.2',
        description = 'VPP Python binding',
        author = 'Ole Troan',
        author_email = 'ot@cisco.com',
-       #url = 'https://docs.python.org/extending/building',
        test_suite = 'tests',
        packages=['vpp_papi'],
-       long_description = '''
-VPP Python language binding.
-''',)
+       ext_modules = [
+           Extension(
+               'vpp_api',
+               sources = ['vpp_papi/pneum_wrap.c'],
+               libraries = ['pneum'],
+           )],
+       long_description = '''VPP Python language binding.''',
+)
diff --git a/vpp-api/python/tests/test_base.py b/vpp-api/python/tests/test_base.py
deleted file mode 100644
index 8ff5dd4..0000000
--- a/vpp-api/python/tests/test_base.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Manipulate sys.path to allow tests be run inside the build environment.
-import os, sys, glob
-scriptdir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp-api/lib64/vpp_api.so')[0]))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vlib-api/vlibmemory/memclnt.py')[0]))
-sys.path.append(os.path.dirname(glob.glob(scriptdir+'/../../../build-root/install*/vpp/vpp-api/vpe.py')[0]))
-sys.path.append(glob.glob(scriptdir+'/../../../build-root/install*/plugins/vpp_papi_plugins')[0])
diff --git a/vpp-api/python/tests/test_modules.py b/vpp-api/python/tests/test_modules.py
index 48df175..fdcd092 100755
--- a/vpp-api/python/tests/test_modules.py
+++ b/vpp-api/python/tests/test_modules.py
@@ -1,7 +1,5 @@
-#!/usr/bin/env python
 from __future__ import print_function
 import unittest
-import test_base
 import vpp_papi
 import pot, snat
 print('Plugins:')
diff --git a/vpp-api/python/tests/test_papi.py b/vpp-api/python/tests/test_papi.py
index ab90eea..8cbbfc5 100755
--- a/vpp-api/python/tests/test_papi.py
+++ b/vpp-api/python/tests/test_papi.py
@@ -1,13 +1,10 @@
-#!/usr/bin/env python
-
 from __future__ import print_function
-import unittest, sys, time, threading, struct, logging
-import test_base
+import unittest, sys, time, threading, struct, logging, os
 import vpp_papi
 from ipaddress import *
-
+scriptdir = os.path.dirname(os.path.realpath(__file__))
 papi_event = threading.Event()
-print(vpp_papi.VL_API_SW_INTERFACE_SET_FLAGS)
+print(vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS)
 def papi_event_handler(result):
     if result.vl_msg_id == vpp_papi.vpe.VL_API_SW_INTERFACE_SET_FLAGS:
         return
@@ -27,7 +24,7 @@
     def setUpClass(cls):
         #
         # Start main VPP process
-        cls.vpp_bin = glob.glob(test_base.scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0]
+        cls.vpp_bin = glob.glob(scriptdir+'/../../../build-root/install-vpp*-native/vpp/bin/vpp')[0]
         print("VPP BIN:", cls.vpp_bin)
         cls.vpp = subprocess.Popen([cls.vpp_bin, "unix", "nodaemon"], stderr=subprocess.PIPE)
         print('Started VPP')
@@ -89,7 +86,7 @@
         self.assertEqual(t.retval, 0)
 
         ifindex = t.sw_if_index
-        addr = str(IPv6Address('1::1').packed)
+        addr = str(IPv6Address(u'1::1').packed)
         t = vpp_papi.sw_interface_add_del_address(ifindex, 1, 1, 0, 16, addr)
         print(t)
         self.assertEqual(t.retval, 0)
diff --git a/vpp-api/python/tests/test_version.py b/vpp-api/python/tests/test_version.py
new file mode 100755
index 0000000..de39cc2
--- /dev/null
+++ b/vpp-api/python/tests/test_version.py
@@ -0,0 +1,35 @@
+from __future__ import print_function
+import unittest, sys, time, threading, struct
+
+import vpp_papi
+from ipaddress import *
+import glob, subprocess
+class TestPAPI(unittest.TestCase):
+    def setUp(self):
+        print("Connecting API")
+        r = vpp_papi.connect("test_papi")
+        self.assertEqual(r, 0)
+
+    def tearDown(self):
+        r = vpp_papi.disconnect()
+        self.assertEqual(r, 0)
+
+    #
+    # The tests themselves
+    #
+
+    #
+    # Basic request / reply
+    #
+    def test_show_version(self):
+        print(vpp_papi.show_version())
+
+    #
+    # Details / Dump
+    #
+    def test_details_dump(self):
+        t = vpp_papi.sw_interface_dump(0, b'')
+        print('Dump/details T', t)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/vpp-api/python/vpp_papi/__init__.py b/vpp-api/python/vpp_papi/__init__.py
index 19d78a3..6688ffb 100644
--- a/vpp-api/python/vpp_papi/__init__.py
+++ b/vpp-api/python/vpp_papi/__init__.py
@@ -1,4 +1,3 @@
 __import__('pkg_resources').declare_namespace(__name__)
 from . vpp_papi import *
 
-
diff --git a/vpp-api/python/vpp_papi/vpp_api_base.py b/vpp-api/python/vpp_papi/vpp_api_base.py
index a1ef87a..227257f 100644
--- a/vpp-api/python/vpp_papi/vpp_api_base.py
+++ b/vpp-api/python/vpp_papi/vpp_api_base.py
@@ -58,7 +58,7 @@
     results[context]['e'].clear()
 
 def results_event_wait(context, timeout):
-    results[context]['e'].wait(timeout)
+    return (results[context]['e'].wait(timeout))
 
 def results_set(context, r):
     results[context]['r'] = r
diff --git a/vpp-api/python/vpp_papi/vpp_papi.py b/vpp-api/python/vpp_papi/vpp_papi.py
index 174e61d..42ddcdc 100644
--- a/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/vpp-api/python/vpp_papi/vpp_papi.py
@@ -20,15 +20,15 @@
 import signal, os, sys
 from struct import *
 
-scriptdir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(scriptdir)
 import vpp_api
 from vpp_api_base import *
 
 # Import API definitions. The core VPE API is imported into main namespace
 import memclnt
+
+# Cheating a bit, importing it into this namespace as well as a module.
+import vpe
 from vpe import *
-vpe = sys.modules['vpe']
 
 def eprint(*args, **kwargs):
     print(*args, file=sys.stderr, **kwargs)
@@ -67,7 +67,7 @@
     #
     # Collect results until control ping
     #
-    if id[0] == vpe.VL_API_CONTROL_PING_REPLY:
+    if id[0] == VL_API_CONTROL_PING_REPLY:
         results_event_set(context)
         waiting_for_reply_clear()
         return
@@ -82,7 +82,14 @@
     results_event_set(context)
     waiting_for_reply_clear()
 
+def handler(signum, frame):
+    print('Signal handler called with signal', signum)
+    raise IOError("Couldn't connect to VPP!")
+
 def connect(name):
+    # Set the signal handler
+    signal.signal(signal.SIGALRM, handler)
+
     signal.alarm(3) # 3 second
     rv = vpp_api.connect(name, msg_handler)
     signal.alarm(0)
@@ -90,20 +97,16 @@
     #
     # Assign message id space for plugins
     #
-    plugin_map_plugins()
-
+    try:
+        plugin_map_plugins()
+    except:
+        return -1
     return rv
 
 def disconnect():
     rv = vpp_api.disconnect()
     return rv
 
-# CLI convenience wrapper
-def cli_exec(cmd):
-    cmd += '\n'
-    r = cli_inband(len(cmd), cmd)
-    return r.reply[0].decode().rstrip('\x00')
-
 def register_event_callback(callback):
     event_callback_set(callback)
 
@@ -112,6 +115,7 @@
         m = globals()[plugin]
     except KeyError:
         m = sys.modules[plugin]
+
     for name in name_to_id_table:
         setattr(m, name, name_to_id_table[name] + base)
 
@@ -126,11 +130,10 @@
         #
         version = plugins[p]['version']
         name = p + '_' + format(version, '08x')
-        r = memclnt.get_first_msg_id(name.encode('ascii'))
-        ## TODO: Add error handling / raise exception
+        r = memclnt.get_first_msg_id(name)
         if r.retval != 0:
-            eprint('Failed getting first msg id for:', p)
-            continue
+            eprint('Failed getting first msg id for:', p, r, name)
+            raise
 
         # Set base
         base = r.first_msg_id
@@ -153,6 +156,8 @@
 #
 memclnt.msg_id_base_set(1)
 plugins['memclnt']['base'] = 1
+
+# vpe
 msg_id_base_set(len(plugins['memclnt']['func_table']) + 1)
 plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1
 api_func_table = []
@@ -160,3 +165,4 @@
 api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table']
 plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1)
 plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])
+plugin_name_to_id(__name__, plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])