diff --git a/changelog.md b/changelog.md
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y2hhbmdlbG9nLm1k..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y2hhbmdlbG9nLm1k 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,13 @@
 PyMQI changelog
 ---------------
 
+* **1.11.0** (2020-06-11)
+
+  * Moved from MQAI to raw PCF, making it possible to use PCF commands on z/OS in addition to other systems
+  * Added a wait (expiry) interval to PCF messages (needed for large responses)
+  * Added ability to request a conversion of response PCF messages (required for z/OS)
+  * Thanks to @salapat11 for the assistance in preparing this release
+
 * **1.10.1** (2020-02-15)
 
   * Added [automatic conversion of Unicode to bytes](https://dsuch.github.io/pymqi/examples.html#sending-unicode-data-vs-bytes)
diff --git a/code/pymqi/__init__.py b/code/pymqi/__init__.py
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS9weW1xaS9fX2luaXRfXy5weQ==..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS9weW1xaS9fX2luaXRfXy5weQ== 100644
--- a/code/pymqi/__init__.py
+++ b/code/pymqi/__init__.py
@@ -97,6 +97,8 @@
 import ctypes
 import sys
 
+from typing import Any, Optional, Union, Dict
+
 # import xml parser.  lxml/etree only available since python 2.5
 use_minidom = False
 try:
@@ -100,6 +102,5 @@
 # import xml parser.  lxml/etree only available since python 2.5
 use_minidom = False
 try:
-    # noinspection PyUnresolvedReferences
-    import lxml.etree
+    import lxml.etree # type: ignore
 except ImportError:
@@ -105,6 +106,6 @@
 except ImportError:
-    from xml.dom.minidom import parseString
+    from xml.dom.minidom import parseString # type: ignore
     use_minidom = True
 
 # Python 3.8+ DLL loading
 try:
@@ -107,8 +108,8 @@
     use_minidom = True
 
 # Python 3.8+ DLL loading
 try:
-    from os import add_dll_directory
+    from os import add_dll_directory  # type: ignore
     from os import environ
     from os.path import join
     from os.path import exists
@@ -125,5 +126,5 @@
 
 # PyMQI
 try:
-    from . import pymqe
+    from . import pymqe # type: ignore
 except ImportError:
@@ -129,5 +130,5 @@
 except ImportError:
-    import pymqe  # Backward compatibility
+    import pymqe # type: ignore # Backward compatibility
 from pymqi import CMQCFC
 from pymqi import CMQC, CMQXC, CMQZC
 
@@ -136,7 +137,7 @@
     CMQZC = CMQZC
     unicode = object()
 
-__version__ = '1.10.1'
+__version__ = '1.11.0'
 __mqlevels__ = pymqe.__mqlevels__
 __mqbuild__ = pymqe.__mqbuild__
 
@@ -178,6 +179,12 @@
     else:
         return s
 
+def padded_count(count, boundary=4):
+    # type: (int, int) -> int
+    """Calculate padded bytes count
+    """
+    return count + ((boundary - count & (boundary - 1)) & (boundary - 1))
+
 #
 # 64bit suppport courtesy of Brent S. Elmer, Ph.D. (mailto:webe3vt@aim.com)
 #
@@ -249,6 +256,7 @@
     """
 
     def __init__(self, memlist, **kw):
+        # type: (list, Any) -> None
         """ Initialise the option structure. 'list' is a list of structure
     member names, default values and pack/unpack formats. 'kw' is an
     optional keyword dictionary that may be used to override default
@@ -260,10 +268,10 @@
 
         # Dict to store c_char arrays to prevent memory addresses
         # from getting overwritten
-        self.__vs_ctype_store = {}
+        self.__vs_ctype_store = {} # type: Dict[str, Any]
 
         # Create the structure members as instance attributes and build
         # the struct.pack/unpack format string. The attribute name is
         # identical to the 'C' structure member name.
         for i in memlist:
             setattr(self, i[0], i[1])
@@ -264,10 +272,14 @@
 
         # Create the structure members as instance attributes and build
         # the struct.pack/unpack format string. The attribute name is
         # identical to the 'C' structure member name.
         for i in memlist:
             setattr(self, i[0], i[1])
-            self.__format = self.__format + i[2]
-        self.set(**kw)
+            try:
+                i[3]
+            except:
+                i.append(1)
+            self.__format = self.__format + i[2] * i[3]
+        self.set(**kw), list
 
     def pack(self):
@@ -272,5 +284,6 @@
 
     def pack(self):
+        # type: () -> bytes
         """ Pack the attributes into a 'C' structure to be passed to MQI
         calls. The pack order is as defined to the MQOpts
         ctor. Returns the structure as a string buffer.
@@ -294,6 +307,7 @@
         return struct.pack(*args)
 
     def unpack(self, buff):
+        # type (bytes)
         """ Unpack a 'C' structure 'buff' into self.
         """
         ensure_not_unicode(buff)  # Python 3 bytes check
@@ -308,8 +322,17 @@
         r = struct.unpack(self.__format, buff)
         x = 0
         for i in self.__list:
-            ensure_not_unicode(r[x])  # Python 3 bytes check
-            setattr(self, i[0], r[x])
-            x = x + 1
+
+            if isinstance(i[1], list):
+                l = []
+                for j in range(i[3]):
+                    ensure_not_unicode(r[x])  # Python 3 bytes check
+                    l.append(r[x])
+                    x = x + 1
+                setattr(self, i[0], l)
+            else:
+                ensure_not_unicode(r[x])  # Python 3 bytes check
+                setattr(self, i[0], r[x])
+                x = x + 1
 
     def set(self, **kw):
@@ -314,5 +337,6 @@
 
     def set(self, **kw):
+        # types: (Dict[str, Any])
         """ Set a structure member using the keyword dictionary 'kw'.
         An AttributeError exception is raised for invalid member names.
         """
@@ -325,6 +349,7 @@
             setattr(self, str(i), kw[i])
 
     def __setitem__(self, key, value):
+        # types: (str, Any)
         """ Set the structure member attribute 'key' to 'value', as in obj['Attr'] = 42.
         """
         # Only set if the attribute already exists. getattr raises an
@@ -334,6 +359,7 @@
         setattr(self, key, value)
 
     def get(self):
+        # types: () -> dict
         """ Return a dictionary of the current structure member values. The dictionary is keyed by a 'C' member name.
         """
         d = {}
@@ -342,8 +368,9 @@
         return d
 
     def __getitem__(self, key):
+        # types: (str) -> Any
         """Return the member value associated with key, as in print obj['Attr'].
         """
         return getattr(self, key)
 
     def __str__(self):
@@ -345,8 +372,9 @@
         """Return the member value associated with key, as in print obj['Attr'].
         """
         return getattr(self, key)
 
     def __str__(self):
+        # types: () -> str
         rv = ''
         for i in self.__list:
             rv = rv + str(i[0]) + ': ' + str(getattr(self, i[0])) + '\n'
@@ -354,8 +382,9 @@
         return rv[:-1]
 
     def __repr__(self):
+        # types: () -> str
         """ Return the packed buffer as a printable string.
         """
         return str(self.pack())
 
     def get_length(self):
@@ -357,10 +386,11 @@
         """ Return the packed buffer as a printable string.
         """
         return str(self.pack())
 
     def get_length(self):
+        # types: () -> int
         """ Returns the length of the (would be) packed buffer.
         """
         return struct.calcsize(self.__format)
 
     def set_vs(self, vs_name, vs_value=None, vs_offset=0, vs_buffer_size=0, vs_ccsid=0):
@@ -362,8 +392,9 @@
         """ Returns the length of the (would be) packed buffer.
         """
         return struct.calcsize(self.__format)
 
     def set_vs(self, vs_name, vs_value=None, vs_offset=0, vs_buffer_size=0, vs_ccsid=0):
+        # types: (str, Union[bytes, str, None], int, int, int)
         """ This method aids in the setting of the MQCHARV (variable length
         string) types in MQ structures.  The type contains a pointer to a
         variable length string.  A common example of a MQCHARV type
@@ -410,6 +441,7 @@
         self.__vs_ctype_store[vs_name] = c_vs_value
 
     def get_vs(self, vs_name):
+        # types: (str) -> Union[bytes, str, None]
         """ This method returns the string to which the VSPtr pointer points to.
         """
         # if the VSPtr name is passed - remove VSPtr to be left with name.
@@ -425,6 +457,7 @@
 
         return c_vs_value
 
+
 #
 # Sub-classes of MQOpts representing real MQI structures.
 #
@@ -1134,6 +1167,186 @@
 
         super(XQH, self).__init__(tuple(opts), **kw)
 
+
+class CFH(MQOpts):
+    """ Construct an MQCFH Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        opts = [['Type', CMQCFC.MQCFT_COMMAND, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFH_STRUC_LENGTH, MQLONG_TYPE],
+                ['Version', CMQCFC.MQCFH_VERSION_1, MQLONG_TYPE],
+                ['Command', CMQCFC.MQCMD_NONE, MQLONG_TYPE],
+                ['MsgSeqNumber', 1, MQLONG_TYPE],
+                ['Control', CMQCFC.MQCFC_LAST, MQLONG_TYPE],
+                ['CompCode', CMQC.MQCC_OK, MQLONG_TYPE],
+                ['Reason', CMQC.MQRC_NONE, MQLONG_TYPE],
+                ['ParameterCount', 0, MQLONG_TYPE]
+               ]
+        super(CFH, self).__init__(tuple(opts), **kw)
+
+class CFBF(MQOpts):
+    """ Construct an MQCFBF Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        filter_value = kw.pop('FilterValue', '')
+        filter_value_length = kw.pop('FilterValueLength', len(filter_value))
+        padded_filter_value_length = padded_count(filter_value_length)
+
+        opts = [['Type', CMQCFC.MQCFT_BYTE_STRING_FILTER, MQLONG_TYPE],
+                ['StrucLength',
+                 CMQCFC.MQCFBF_STRUC_LENGTH_FIXED + padded_filter_value_length, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['Operator', 0, MQLONG_TYPE],
+                ['FilterValueLength', filter_value_length, MQLONG_TYPE],
+                ['FilterValue', filter_value, '{}s'.format(padded_filter_value_length)]
+               ]
+
+        super(CFBF, self).__init__(tuple(opts), **kw)
+
+class CFBS(MQOpts):
+    """ Construct an MQCFBS Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        string = kw.pop('String', '')
+        string_length = kw.pop('StringLength', len(string))
+        padded_string_length = padded_count(string_length)
+
+        opts = [['Type', CMQCFC.MQCFT_BYTE_STRING, MQLONG_TYPE],
+                ['StrucLength',
+                 CMQCFC.MQCFBS_STRUC_LENGTH_FIXED + padded_string_length, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['StringLength', string_length, MQLONG_TYPE],
+                ['String', string, '{}s'.format(padded_string_length)]
+               ]
+
+        super(CFBS, self).__init__(tuple(opts), **kw)
+
+class CFIF(MQOpts):
+    """ Construct an MQCFIF Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        opts = [['Type', CMQCFC.MQCFT_INTEGER_FILTER, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFIF_STRUC_LENGTH, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['Operator', 0, MQLONG_TYPE],
+                ['FilterValue', 0, MQLONG_TYPE]
+               ]
+
+        super(CFIF, self).__init__(tuple(opts), **kw)
+
+class CFIL(MQOpts):
+    """ Construct an MQCFIL Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        values = kw.pop('Values', [])
+        count = kw.pop('Count', len(values))
+
+        opts = [['Type', CMQCFC.MQCFT_INTEGER_LIST, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFIL_STRUC_LENGTH_FIXED + 4 * count, MQLONG_TYPE], # Check python 2
+                ['Parameter', 0, MQLONG_TYPE],
+                ['Count', count, MQLONG_TYPE],
+                ['Values', values, MQLONG_TYPE, count],
+               ]
+        super(CFIL, self).__init__(tuple(opts), **kw)
+
+class CFIN(MQOpts):
+    """ Construct an MQCFIN Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None -> None
+
+        opts = [['Type', CMQCFC.MQCFT_INTEGER, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFIN_STRUC_LENGTH, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['Value', 0, MQLONG_TYPE],
+               ]
+        super(CFIN, self).__init__(tuple(opts), **kw)
+
+class CFSF(MQOpts):
+    """ Construct an MQCFSF Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        filter_value = kw.pop('FilterValue', '')
+        filter_value_length = kw.pop('FilterValueLength', len(filter_value))
+        padded_filter_value_length = padded_count(filter_value_length)
+
+        opts = [['Type', CMQCFC.MQCFT_STRING_FILTER, MQLONG_TYPE],
+                ['StrucLength',
+                 CMQCFC.MQCFSF_STRUC_LENGTH_FIXED + padded_filter_value_length, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['Operator', 0, MQLONG_TYPE],
+                ['CodedCharSetId', CMQC.MQCCSI_DEFAULT, MQLONG_TYPE],
+                ['FilterValueLength', filter_value_length, MQLONG_TYPE],
+                ['FilterValue', filter_value, '{}s'.format(padded_filter_value_length)]
+               ]
+
+        super(CFSF, self).__init__(tuple(opts), **kw)
+
+class CFSL(MQOpts):
+    """ Construct an MQCFSL Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        strings = kw.pop('Strings', [])
+        string_length = kw.pop('StringLength', len(max(strings, key=len)) if strings else 0)
+
+        strings_count = len(strings)
+        count = kw.pop('Count', strings_count)
+
+        max_string_length = padded_count(string_length) if count else 0
+        padded_strings_length = (max_string_length) * strings_count
+
+        opts = [['Type', CMQCFC.MQCFT_STRING_LIST, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFSL_STRUC_LENGTH_FIXED + padded_strings_length, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['CodedCharSetId', CMQC.MQCCSI_DEFAULT, MQLONG_TYPE],
+                ['Count', count, MQLONG_TYPE],
+                ['StringLength', max_string_length, MQLONG_TYPE],
+                ['Strings', strings if strings else [b''], '{}s'.format(max_string_length), (count if count else 1)]
+               ]
+
+        super(CFSL, self).__init__(tuple(opts), **kw)
+
+class CFST(MQOpts):
+    """ Construct an MQCFST Structure with default values as per MQI.
+    The default values may be overridden by the optional keyword arguments 'kw'.
+    """
+
+    def __init__(self, **kw):
+        # types: (Dict[str, Any]) -> None
+        string = kw.pop('String', '')
+        string_length = kw.pop('StringLength', len(string))
+        padded_string_length = padded_count(string_length)
+
+        opts = [['Type', CMQCFC.MQCFT_STRING, MQLONG_TYPE],
+                ['StrucLength', CMQCFC.MQCFST_STRUC_LENGTH_FIXED + padded_string_length, MQLONG_TYPE],
+                ['Parameter', 0, MQLONG_TYPE],
+                ['CodedCharSetId', CMQC.MQCCSI_DEFAULT, MQLONG_TYPE],
+                ['StringLength', string_length, MQLONG_TYPE],
+                ['String', string, '{}s'.format(padded_string_length)]
+               ]
+
+        super(CFST, self).__init__(tuple(opts), **kw)
+
 #
 # A utility to convert a MQ constant to its string mnemonic by groping
 # a module dictonary
@@ -1187,5 +1400,7 @@
     """ Exception class for MQI low level errors.
     """
     errStringDicts = (_MQConst2String(CMQC, 'MQRC_'), _MQConst2String(CMQCFC, 'MQRCCF_'),)
+    comp = CMQC.MQCC_OK
+    reason = CMQC.MQRC_NONE
 
     def __init__(self, comp, reason, **kw):
@@ -1190,5 +1405,6 @@
 
     def __init__(self, comp, reason, **kw):
+        # types: (int, int, Dict[str, Any]) -> None
         """ Construct the error object with MQI completion code 'comp' and reason code 'reason'.
         """
         self.comp, self.reason = comp, reason
@@ -1197,6 +1413,7 @@
             setattr(self, key, kw[key])
 
     def __str__(self):
+        # types: () -> str
         return 'MQI Error. Comp: %d, Reason %d: %s' % (self.comp, self.reason, self.errorAsString())
 
     def errorAsString(self):
@@ -1200,6 +1417,7 @@
         return 'MQI Error. Comp: %d, Reason %d: %s' % (self.comp, self.reason, self.errorAsString())
 
     def errorAsString(self):
+        # types: () -> str
         """ Return the exception object MQI warning/failed reason as its mnemonic string.
         """
         if self.comp == CMQC.MQCC_OK:
@@ -1234,7 +1452,9 @@
     default, the Queue Manager is implicitly connected. If required,
     the connection may be deferred until a call to connect().
     """
-    def __init__(self, name='', disconnect_on_exit=True, bytes_encoding=default.bytes_encoding, default_ccsid=default.ccsid):
+    def __init__(self, name='', disconnect_on_exit=True,
+                 bytes_encoding=default.bytes_encoding, default_ccsid=default.ccsid):
+        # type: (Optional[str], bool, str, int) -> None
         """ Connect to the Queue Manager 'name' (default value '').
         If 'name' is None, don't connect now, but defer the connection until connect() is called.
         Input 'bytes_encoding'  and 'default_ccsid' are the encodings that will be used in PCF, MQPUT and MQPUT1 calls
@@ -1253,6 +1473,7 @@
             self.connect(name)
 
     def __del__(self):
+        # types: ()
         """ Disconnect from the queue Manager, if connected.
         """
         if self.__handle:
@@ -1269,6 +1490,7 @@
                     pass
 
     def connect(self, name):
+        # types: (str)
         """connect(name)
 
         Connect immediately to the Queue Manager 'name'."""
@@ -1284,6 +1506,7 @@
 # Connect options suggested by Jaco Smuts (mailto:JSmuts@clover.co.za)
 
     def connect_with_options(self, name, *args, **kwargs):
+        # types: (str, Any, Dict[str, Any])
         """connect_with_options(name [, opts=cnoopts][ ,cd=mqcd][ ,sco=mqsco])
            connect_with_options(name, cd, [sco])
 
@@ -1341,6 +1564,10 @@
 
         rv = pymqe.MQCONNX(name, options, cd, user_password, sco.pack())
 
+        if rv[1] <= CMQC.MQCC_WARNING:
+            self.__handle = rv[0]
+            self.__name = name
+
         if rv[1]:
             raise MQMIError(rv[1], rv[2])
 
@@ -1344,10 +1571,8 @@
         if rv[1]:
             raise MQMIError(rv[1], rv[2])
 
-        self.__handle = rv[0]
-        self.__name = name
 
     # Backward compatibility
     connectWithOptions = connect_with_options
 
     def connect_tcp_client(self, name, cd, channel, conn_name, user, password):
@@ -1349,9 +1574,9 @@
 
     # Backward compatibility
     connectWithOptions = connect_with_options
 
     def connect_tcp_client(self, name, cd, channel, conn_name, user, password):
-        # type: (str, CD, str, str, str, str)
+        # type: (str, CD, str, str, str, str) -> None
         """ Connect immediately to the remote Queue Manager 'name', using
         a TCP Client connection, with channnel 'channel' and the
         TCP connection string 'conn_name'. All other connection
@@ -1375,6 +1600,7 @@
     connectTCPClient = connect_tcp_client
 
     def disconnect(self):
+        # type: () -> None
         """ Disconnect from queue manager, if connected.
         """
         if not self.__handle:
@@ -1383,6 +1609,7 @@
         self.__handle = self.__qmobj = None
 
     def get_handle(self):
+        # type: () -> None
         """ Get the queue manager handle. The handle is used for other pymqi calls.
         """
         if self.__handle:
@@ -1394,6 +1621,7 @@
     getHandle = get_handle
 
     def begin(self):
+        # type: () -> None
         """ Begin a new global transaction.
         """
         rv = pymqe.MQBEGIN(self.__handle)
@@ -1401,6 +1629,7 @@
             raise MQMIError(rv[0], rv[1])
 
     def commit(self):
+        # type: () -> None
         """ Commits any outstanding gets/puts in the current unit of work.
         """
         rv = pymqe.MQCMIT(self.__handle)
@@ -1408,6 +1637,7 @@
             raise MQMIError(rv[0], rv[1])
 
     def backout(self):
+        # type: () -> None
         """ Backout any outstanding gets/puts in the current unit of work.
         """
         rv = pymqe.MQBACK(self.__handle)
@@ -1415,6 +1645,7 @@
             raise MQMIError(rv[0], rv[1])
 
     def put1(self, qDesc, msg, *opts):
+        # type: (Union[str, bytes, OD], Optional[bytes], Union[MD, OD]) -> None
         """ Put the single message in string buffer 'msg' on the queue
         using the MQI PUT1 call. This encapsulates calls to MQOPEN,
         MQPUT and MQCLOSE. put1 is the optimal way to put a single
@@ -1438,10 +1669,10 @@
 
         if not isinstance(msg, bytes):
             if (
-                (is_py3 and isinstance(msg, str))  # Python 3 string is unicode
-                or
-                (is_py2 and isinstance(msg, unicode)) # Python 2.7 string can be unicode
-              ):
+                    (is_py3 and isinstance(msg, str))  # Python 3 string is unicode
+                    or
+                    (is_py2 and isinstance(msg, unicode)) # type: ignore # Python 2.7 string can be unicode
+                ):
                 msg = msg.encode(self.bytes_encoding)
                 m_desc.CodedCharSetId = self.default_ccsid
                 m_desc.Format = CMQC.MQFMT_STRING
@@ -1460,6 +1691,7 @@
         put_opts.unpack(rv[1])
 
     def inquire(self, attribute):
+        # types: (str) -> Any
         """ Inquire on queue manager 'attribute'. Returns either the integer or string value for the attribute.
         """
         attribute = ensure_bytes(attribute)  # Python 3 strings to be converted to bytes
@@ -1477,9 +1709,10 @@
         return rv[0]
 
     def _is_connected(self):
+        # types: () -> bool
         """ Try pinging the queue manager in order to see whether the application
         is connected to it. Note that the method is merely a convienece wrapper
         around MQCMD_PING_Q_MGR, in particular, there's still possibility that
         the app will disconnect between checking QueueManager.is_connected
         and the next MQ call.
         """
@@ -1480,8 +1713,8 @@
         """ Try pinging the queue manager in order to see whether the application
         is connected to it. Note that the method is merely a convienece wrapper
         around MQCMD_PING_Q_MGR, in particular, there's still possibility that
         the app will disconnect between checking QueueManager.is_connected
         and the next MQ call.
         """
-        pcf = PCFExecute(self)
+
         try:
@@ -1487,4 +1720,5 @@
         try:
+            pcf = PCFExecute(self)
             pcf.MQCMD_PING_Q_MGR()
         except Exception:
             return False
@@ -1495,6 +1729,7 @@
 
 # Some support functions for Queue ops.
 def make_q_desc(qDescOrString):
+    # types: (Union[str, bytes, OD]) -> OD
     """Maybe make MQOD from string. Module Private"""
     if isinstance(qDescOrString, (str, bytes)):
         return OD(ObjectName=ensure_bytes(qDescOrString))  # Python 3 strings to be converted to bytes
@@ -1621,10 +1856,10 @@
 
         if not isinstance(msg, bytes):
             if (
-                (is_py3 and isinstance(msg, str))  # Python 3 string is unicode
-                or
-                (is_py2 and isinstance(msg, unicode)) # Python 2.7 string can be unicode
-              ):
+                    (is_py3 and isinstance(msg, str))  # Python 3 string is unicode
+                    or
+                    (is_py2 and isinstance(msg, unicode)) # Python 2.7 string can be unicode
+                ):
                 msg = msg.encode(self.__qMgr.bytes_encoding)
                 m_desc.CodedCharSetId = self.__qMgr.default_ccsid
                 m_desc.Format = CMQC.MQFMT_STRING
@@ -1723,10 +1958,10 @@
 
         # Accept truncated message
         if ((rv[-1] == CMQC.MQRC_TRUNCATED_MSG_ACCEPTED) or
-            # Do not reread message with original length
-            (rv[-1] == CMQC.MQRC_TRUNCATED_MSG_FAILED and maxLength is not None) or
-            # Other errors
-            (rv[-1] != CMQC.MQRC_TRUNCATED_MSG_FAILED)):
+                # Do not reread message with original length
+                (rv[-1] == CMQC.MQRC_TRUNCATED_MSG_FAILED and maxLength is not None) or
+                # Other errors
+                (rv[-1] != CMQC.MQRC_TRUNCATED_MSG_FAILED)):
             if rv[-2] == CMQC.MQCC_WARNING:
                 m_desc.unpack(rv[1])
                 get_opts.unpack(rv[2])
@@ -1785,6 +2020,7 @@
         return msg
 
     def close(self, options=CMQC.MQCO_NONE):
+        # type: (int) -> None
         """ Close a queue, using options.
         """
         if not self.__qHandle:
@@ -1827,7 +2063,7 @@
         """
         self.__qHandle = queue_handle
 
-    def get_handle(self):
+    def get_handle(self): # type: () -> Queue
         """ Get the queue handle.
         """
         return self.__qHandle
@@ -2235,7 +2471,7 @@
     the selector, value and the operator to use. For instance, the can be respectively
     MQCA_Q_DESC, 'MY.QUEUE.*', MQCFOP_LIKE. Compare with the pymqi.Filter class.
     """
-    _pymqi_filter_type = None
+    _pymqi_filter_type = None # type: Optional[str]
 
     def __init__(self, selector, value, operator):
         self.selector = selector  # this is int
@@ -2325,7 +2561,8 @@
 #
 class _Method:
     def __init__(self, pcf, name):
+        # types: (PCFExecute, str) -> None
         self.__pcf = pcf
         self.__name = name
 
     def __getattr__(self, name):
@@ -2328,7 +2565,8 @@
         self.__pcf = pcf
         self.__name = name
 
     def __getattr__(self, name):
+        # types: (str) -> _Method
         return _Method(self.__pcf, '%s.%s' % (self.__name, name))
 
     def __call__(self, *args):
@@ -2332,6 +2570,7 @@
         return _Method(self.__pcf, '%s.%s' % (self.__name, name))
 
     def __call__(self, *args):
+        # types: (Unions[dict, list, _Filter]) -> list
         if self.__name[0:7] == 'CMQCFC.':
             self.__name = self.__name[7:]
         if self.__pcf.qm:
@@ -2352,7 +2591,10 @@
         else:
             args_dict, filters = {}, []
 
-        # Assuming that a given PCF call requires any arguments, There will be a dictionary at args[0]
-        # On the lower lever, pymqe expects that values of this dictionary will be bytes objects.
-        # Hence we need to iterate over this dictionary and convert any Unicode objects to bytes.
+        mqcfh = CFH(Version=CMQCFC.MQCFH_VERSION_3,
+                    Command=CMQCFC.__dict__[self.__name],
+                    Type=CMQCFC.MQCFT_COMMAND_XR,
+                    ParameterCount=len(args_dict) + len(filters))
+        message = mqcfh.pack()
+
         if args_dict:
@@ -2358,12 +2600,95 @@
         if args_dict:
-            for key, value in args_dict.items():
-                if is_unicode(value):
-                    args_dict[key] = value.encode(bytes_encoding)
-
-        rv = pymqe.mqaiExecute(qm_handle, CMQCFC.__dict__[self.__name], args_dict, filters)
-        if rv[1]:
-            raise MQMIError(rv[-2], rv[-1])
-        return rv[0]
+            if isinstance(args_dict, dict):
+                for key, value in args_dict.items():
+                    if isinstance(value, (str, bytes)):
+                        if is_unicode(value):
+                            value = value.encode(bytes_encoding)
+                        parameter = CFST(Parameter=key,
+                                         String=value)
+                    elif (isinstance(value, ByteString)):
+                        parameter = CFBS(Parameter=key,
+                                         String=value.value.encode(bytes_encoding))
+                    elif isinstance(value, int):
+                        # Backward compatibility for MQAI behaviour
+                        # for single value instead of list
+                        is_list = False
+                        for item in CMQCFC.__dict__:
+                            if ((item[:7] == 'MQIACF_'
+                                or
+                                item[:7] == 'MQIACH_')
+                                and item[-6:] == '_ATTRS'
+                                and CMQCFC.__dict__[item] == key):
+                                    is_list = True
+                                    break
+                        if not is_list:
+                            parameter = CFIN(Parameter=key,
+                                            Value=value)
+                        else:
+                            parameter = CFIL(Parameter=key,
+                                            Values=[value])
+                    elif (isinstance(value, list)
+                          and isinstance(value[0], int)):
+                        parameter = CFIL(Parameter=key,
+                                         Values=value)
+
+                    message = message + parameter.pack()
+            elif isinstance(args_dict, list):
+                for parameter in args_dict:
+                    message = message + parameter.pack()
+
+        if filters:
+            for pcf_filter in filters:
+                if isinstance(pcf_filter, _Filter):
+                    if pcf_filter._pymqi_filter_type == 'string':
+                        pcf_filter = CFSF(Parameter=pcf_filter.selector,
+                                          Operator=pcf_filter.operator,
+                                          FilterValue=pcf_filter.value)
+                    elif pcf_filter._pymqi_filter_type == 'integer':
+                        pcf_filter = CFIF(Parameter=pcf_filter.selector,
+                                          Operator=pcf_filter.operator,
+                                          FilterValue=pcf_filter.value)
+
+                message = message + pcf_filter.pack()
+
+        command_queue = Queue(self.__pcf.qm,
+                              self.__pcf._command_queue_name,
+                              CMQC.MQOO_OUTPUT)
+
+        put_md = MD(Format=CMQC.MQFMT_ADMIN,
+                    MsgType=CMQC.MQMT_REQUEST,
+                    ReplyToQ=self.__pcf._reply_queue_name,
+                    Feedback=CMQC.MQFB_NONE,
+                    Expiry=self.__pcf.response_wait_interval,
+                    Report=CMQC.MQRO_PASS_DISCARD_AND_EXPIRY | CMQC.MQRO_DISCARD_MSG)
+        put_opts = PMO(Options=CMQC.MQPMO_NO_SYNCPOINT)
+
+        command_queue.put(message, put_md, put_opts)
+        command_queue.close()
+
+        gmo_options = CMQC.MQGMO_NO_SYNCPOINT + CMQC.MQGMO_FAIL_IF_QUIESCING + \
+                      CMQC.MQGMO_WAIT
+
+        if self.__pcf.convert:
+            gmo_options = gmo_options + CMQC.MQGMO_CONVERT
+
+        get_opts = GMO(
+            Options=gmo_options,
+            Version=CMQC.MQGMO_VERSION_2,
+            MatchOptions=CMQC.MQMO_MATCH_CORREL_ID,
+            WaitInterval=self.__pcf.response_wait_interval)
+        get_md = MD(CorrelId=put_md.MsgId)
+
+        ress = []
+        while True:
+            message = self.__pcf._reply_queue.get(None, get_md, get_opts)
+            res, control = self.__pcf.unpack(message)
+
+            ress.append(res)
+
+            if control == CMQCFC.MQCFC_LAST:
+                break
+
+        return ress
 
 #
 # Execute a PCF commmand. Inspired by Maas-Maarten Zeeman
@@ -2377,6 +2702,13 @@
     its used. PCF commands are executed by calling a CMQC defined
     MQCMD_* method on the object.  """
 
+    _reply_queue = None # type: Queue
+    _reply_queue_name = None # type: str
+    _command_queue_name = b'SYSTEM.ADMIN.COMMAND.QUEUE' # type: bytes
+    response_wait_interval = 0
+
+    qm = None # type: Optional[QueueManager]
+
     iaStringDict = _MQConst2String(CMQC, 'MQIA_')
     caStringDict = _MQConst2String(CMQC, 'MQCA_')
 
@@ -2380,10 +2712,17 @@
     iaStringDict = _MQConst2String(CMQC, 'MQIA_')
     caStringDict = _MQConst2String(CMQC, 'MQCA_')
 
-    def __init__(self, name=''):
+    def __init__(self, name=None,
+                 disconnect_on_exit=True,
+                 model_queue_name=b'SYSTEM.DEFAULT.MODEL.QUEUE',
+                 dynamic_queue_name=b'PYMQPCF.*',
+                 command_queue_name=b'',
+                 response_wait_interval=100,
+                 convert=False):
+        # type: (Any, bool, bytes, bytes, bytes) -> None
         """PCFExecute(name = '')
 
         Connect to the Queue Manager 'name' (default value '') ready
         for a PCF command. If name is a QueueManager instance, it is
         used for the connection, otherwise a new connection is made """
 
@@ -2384,9 +2723,15 @@
         """PCFExecute(name = '')
 
         Connect to the Queue Manager 'name' (default value '') ready
         for a PCF command. If name is a QueueManager instance, it is
         used for the connection, otherwise a new connection is made """
 
+        self.response_wait_interval = response_wait_interval
+        self.convert = convert
+
+        if command_queue_name:
+            self._command_queue_name = command_queue_name
+
         if isinstance(name, QueueManager):
             self.qm = name
             super(PCFExecute, self).__init__(None)
@@ -2394,6 +2739,14 @@
             self.qm = None
             super(PCFExecute, self).__init__(name)
 
+        if not self._reply_queue and not self._reply_queue_name:
+            od = OD(ObjectName=model_queue_name,
+                    DynamicQName=dynamic_queue_name)
+
+            self._reply_queue = Queue(self.qm, od, CMQC.MQOO_INPUT_EXCLUSIVE)
+            self._reply_queue_name = od.ObjectName.strip()
+
+
     def __getattr__(self, name):
         """MQCMD_*(attrDict)
 
@@ -2440,6 +2793,83 @@
     # Backward compatibility
     stringifyKeys = stringify_keys
 
+    def disconnect(self):
+        """ Disconnect from reply_queue
+        """
+        try:
+            if self._reply_queue and self._reply_queue.get_handle():
+                self._reply_queue.close()
+        except MQMIError as ex:
+            pass
+        finally:
+            self._reply_queue = None
+            self._reply_queue_name = None
+
+    @staticmethod
+    def unpack(message): # type: (bytes) -> dict
+        """Unpack PCF message to dictionary
+        """
+
+        mqcfh = CFH(Version=CMQCFC.MQCFH_VERSION_1)
+        mqcfh.unpack(message[:CMQCFC.MQCFH_STRUC_LENGTH])
+
+        if mqcfh.Version != CMQCFC.MQCFH_VERSION_1:
+            mqcfh = CFH(Version=mqcfh.Version)
+            mqcfh.unpack(message[:CMQCFC.MQCFH_STRUC_LENGTH])
+
+        if mqcfh.CompCode:
+            raise MQMIError(mqcfh.CompCode, mqcfh.Reason)
+
+        res = {}
+        index = mqcfh.ParameterCount
+        cursor = CMQCFC.MQCFH_STRUC_LENGTH
+        parameter = None # type: Optional[MQOpts]
+        while (index > 0):
+            if message[cursor] == CMQCFC.MQCFT_STRING:
+                parameter = CFST()
+                parameter.unpack(message[cursor:cursor + CMQCFC.MQCFST_STRUC_LENGTH_FIXED])
+                if parameter.StringLength > 1:
+                    parameter = CFST(StringLength=parameter.StringLength)
+                    parameter.unpack(message[cursor:cursor + parameter.StrucLength])
+                value = parameter.String
+            elif message[cursor] == CMQCFC.MQCFT_STRING_LIST:
+                parameter = CFSL()
+                parameter.unpack(message[cursor:cursor + CMQCFC.MQCFSL_STRUC_LENGTH_FIXED])
+                if parameter.StringLength > 1:
+                    parameter = CFSL(StringLength=parameter.StringLength,
+                                     Count=parameter.Count,
+                                     StrucLength=parameter.StrucLength)
+                    parameter.unpack(message[cursor:cursor + parameter.StrucLength])
+                value = parameter.Strings
+            elif message[cursor] == CMQCFC.MQCFT_INTEGER:
+                parameter = CFIN()
+                parameter.unpack(message[cursor:cursor + CMQCFC.MQCFIN_STRUC_LENGTH])
+                value = parameter.Value
+            elif message[cursor] == CMQCFC.MQCFT_INTEGER_LIST:
+                parameter = CFIL()
+                parameter.unpack(message[cursor:cursor + CMQCFC.MQCFIL_STRUC_LENGTH_FIXED])
+                if parameter.Count > 0:
+                    parameter = CFIL(Count=parameter.Count,
+                                     StrucLength=parameter.StrucLength)
+                    parameter.unpack(message[cursor:cursor + parameter.StrucLength])
+                value = parameter.Values
+            elif message[cursor] == CMQCFC.MQCFT_BYTE_STRING:
+                parameter = CFBS()
+                parameter.unpack(message[cursor:cursor + CMQCFC.MQCFBS_STRUC_LENGTH_FIXED])
+                if parameter.StringLength > 1:
+                    parameter = CFBS(StringLength=parameter.StringLength)
+                    parameter.unpack(message[cursor:cursor + parameter.StrucLength])
+                value = parameter.String
+            else:
+                pcf_type = struct.unpack(MQLONG_TYPE, message[cursor:cursor + 4])
+                raise NotImplementedError('Unpack for type ({}) not implemented'.format(pcf_type))
+            index -= 1
+            cursor += parameter.StrucLength
+            res[parameter.Parameter] = value
+
+        return res, mqcfh.Control
+
+
 class ByteString(object):
     """ A simple wrapper around string values, suitable for passing into PyMQI
     calls wherever IBM's docs state a 'byte string' object should be passed in.
@@ -2452,7 +2882,7 @@
         return len(self.value)
 
 def connect(queue_manager, channel=None, conn_info=None, user=None, password=None, disconnect_on_exit=True,
-    bytes_encoding=default.bytes_encoding, default_ccsid=default.ccsid):
+            bytes_encoding=default.bytes_encoding, default_ccsid=default.ccsid):
     """ A convenience wrapper for connecting to MQ queue managers. If given the
     'queue_manager' parameter only, will try connecting to it in bindings mode.
     If given both 'channel' and 'conn_info' will connect in client mode.
@@ -2464,7 +2894,8 @@
         return qmgr
 
     elif queue_manager:
-        qmgr = QueueManager(queue_manager, disconnect_on_exit, bytes_encoding=bytes_encoding, default_ccsid=default.ccsid)
+        qmgr = QueueManager(queue_manager, disconnect_on_exit,
+                            bytes_encoding=bytes_encoding, default_ccsid=default.ccsid)
         return qmgr
 
     else:
diff --git a/code/pymqi/pymqe.c b/code/pymqi/pymqe.c
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS9weW1xaS9weW1xZS5j..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS9weW1xaS9weW1xZS5j 100644
--- a/code/pymqi/pymqe.c
+++ b/code/pymqi/pymqe.c
@@ -45,7 +45,7 @@
  *
  */
 
-static char __version__[] = "1.10.1";
+static char __version__[] = "1.11.0";
 
 static char pymqe_doc[] = " \
 pymqe - A Python MQ Extension.  This presents a low-level Python \
diff --git a/code/setup.py b/code/setup.py
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS9zZXR1cC5weQ==..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS9zZXR1cC5weQ== 100644
--- a/code/setup.py
+++ b/code/setup.py
@@ -16,7 +16,7 @@
 from distutils import spawn
 from struct import calcsize
 
-version = '1.10.1'
+version = '1.11.0'
 
 # Build either in bindings or client mode.
 bindings_mode = 0
diff --git a/code/tests/requirements.txt b/code/tests/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS90ZXN0cy9yZXF1aXJlbWVudHMudHh0
--- /dev/null
+++ b/code/tests/requirements.txt
@@ -0,0 +1,3 @@
+pytest
+testfixtures
+nose
\ No newline at end of file
diff --git a/code/tests/test_pcf.py b/code/tests/test_pcf.py
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS90ZXN0cy90ZXN0X3BjZi5weQ==..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS90ZXN0cy90ZXN0X3BjZi5weQ== 100644
--- a/code/tests/test_pcf.py
+++ b/code/tests/test_pcf.py
@@ -1,3 +1,5 @@
-"""Test PCF usage
-"""
+"""Test PCF usage."""
+from unittest import skip
+from ddt import data
+from ddt import ddt
 
@@ -3,9 +5,6 @@
 
-import unittest
-
-import config
-import utils
-import env
+from test_setup import Tests  # noqa
+from test_setup import main  # noqa
 
 import pymqi
 
@@ -9,6 +8,15 @@
 
 import pymqi
 
-class TestPCF(unittest.TestCase):
-    def setUp(self):
+@ddt
+class TestPCF(Tests):
+    """Class for MQ PCF testing."""
+
+    pcf = None
+
+    @classmethod
+    def setUpClass(cls):
+        """Initialize test environment."""
+        super(TestPCF, cls).setUpClass()
+
         # max length of queue names is 48 characters
@@ -14,9 +22,4 @@
         # max length of queue names is 48 characters
-        self.queue_name = "{prefix}PCF.QUEUE".format(prefix=config.MQ.QUEUE.PREFIX)
-        self.queue_manager = config.MQ.QM.NAME
-        self.channel = config.MQ.QM.CHANNEL
-        self.host = config.MQ.QM.HOST
-        self.port = config.MQ.QM.PORT
-        self.user = config.MQ.QM.USER
-        self.password = config.MQ.QM.PASSWORD
+        cls.queue_name = "{prefix}PCF.QUEUE".format(prefix=cls.prefix)
+        cls.pcf = pymqi.PCFExecute(cls.qmgr, response_wait_interval=600)
 
@@ -22,3 +25,6 @@
 
-        self.conn_info = "{0}({1})".format(self.host, self.port)
+    @classmethod
+    def tearDownClass(cls):
+        """Tear down test environment."""
+        cls.pcf.disconnect()
 
@@ -24,7 +30,10 @@
 
-        self.qmgr = pymqi.QueueManager(None)
-        self.qmgr.connectTCPClient(self.queue_manager, pymqi.CD(), self.channel, self.conn_info, self.user, self.password)
+        super(TestPCF, cls).tearDownClass()
+
+    def setUp(self):
+        """Set up tesing environment."""
+        super(TestPCF, self).setUp()
 
         self.create_queue(self.queue_name)
 
     def tearDown(self):
@@ -27,8 +36,7 @@
 
         self.create_queue(self.queue_name)
 
     def tearDown(self):
-        """Delete the created objects.
-        """
+        """Delete the created objects."""
         if self.queue_name:
             self.delete_queue(self.queue_name)
@@ -33,4 +41,53 @@
         if self.queue_name:
             self.delete_queue(self.queue_name)
-        self.qmgr.disconnect()
+
+        super(TestPCF, self).tearDown()
+
+    @skip('Not implemented')
+    def test_mqcfbf(self):
+        """Test MQCFBF PCF byte string filter parameter."""
+
+    def test_mqcfbs(self):
+        """Test MQCFBS PCF byte string parameter.
+
+        Also uses MQCFIN and MQCFIL as parameters
+        """
+        attrs = []
+        attrs.append(pymqi.CFBS(Parameter=pymqi.CMQCFC.MQBACF_GENERIC_CONNECTION_ID,
+                                String=b''))
+        attrs.append(pymqi.CFIN(Parameter=pymqi.CMQCFC.MQIACF_CONN_INFO_TYPE,
+                                Value=pymqi.CMQCFC.MQIACF_CONN_INFO_CONN))
+        attrs.append(pymqi.CFIL(Parameter=pymqi.CMQCFC.MQIACF_CONNECTION_ATTRS,
+                                Values=[pymqi.CMQCFC.MQIACF_ALL]))
+
+        object_filters = []
+        object_filters.append(
+            pymqi.CFIF(Parameter=pymqi.CMQC.MQIA_APPL_TYPE,
+                       Operator=pymqi.CMQCFC.MQCFOP_EQUAL,
+                       FilterValue=pymqi.CMQC.MQAT_USER))
+
+        results = self.pcf.MQCMD_INQUIRE_CONNECTION(attrs, object_filters)
+
+        self.assertGreater(len(results), 0)
+
+    def test_mqcfif(self):
+        """Test string filter MQCFIF.
+
+        Also uses MQCFST, MQCFIN and MQCFIL as parameters
+        """
+        attrs = []
+        attrs.append(pymqi.CFST(Parameter=pymqi.CMQC.MQCA_Q_NAME,
+                                String=b'*'))
+        attrs.append(pymqi.CFIN(Parameter=pymqi.CMQC.MQIA_Q_TYPE,
+                                Value=pymqi.CMQC.MQQT_LOCAL))
+        attrs.append(pymqi.CFIL(Parameter=pymqi.CMQCFC.MQIACF_Q_ATTRS,
+                                Values=[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, pymqi.CMQC.MQCA_Q_DESC]))
+
+        object_filters = []
+        object_filters.append(
+            pymqi.CFIF(Parameter=pymqi.CMQC.MQIA_CURRENT_Q_DEPTH,
+                       Operator=pymqi.CMQCFC.MQCFOP_GREATER,
+                       FilterValue=0))
+
+        results = self.pcf.MQCMD_INQUIRE_Q(attrs, object_filters)
 
@@ -36,5 +93,62 @@
 
-    def create_queue(self, queue_name):
-        queue_type = pymqi.CMQC.MQQT_LOCAL
-        max_depth = 5000
+        self.assertTrue(results, 'Queue not found')
+        for result in results:
+            self.assertTrue(result[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH] > 0,
+                            'Found Queue with depth {}'.format(result[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH]))
+    def test_mqcfsf(self):
+        """Test string filter MQCFSF.
+
+        Also uses MQCFST, MQCFIN and MQCFIL as parameters
+        """
+        attrs = []
+        attrs.append(pymqi.CFST(Parameter=pymqi.CMQC.MQCA_Q_NAME,
+                                String=b'*'))
+        attrs.append(pymqi.CFIN(Parameter=pymqi.CMQC.MQIA_Q_TYPE,
+                                Value=pymqi.CMQC.MQQT_LOCAL))
+        attrs.append(pymqi.CFIL(Parameter=pymqi.CMQCFC.MQIACF_Q_ATTRS,
+                                Values=[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, pymqi.CMQC.MQCA_Q_DESC]))
+
+        object_filters = []
+        object_filters.append(
+            pymqi.CFSF(Parameter=pymqi.CMQC.MQCA_Q_DESC,
+                       Operator=pymqi.CMQCFC.MQCFOP_LIKE,
+                       FilterValue=b'IBM MQ*'))
+
+        results = self.pcf.MQCMD_INQUIRE_Q(attrs, object_filters)
+
+        self.assertTrue(results, 'Queue not found')
+        for result in results:
+            self.assertTrue(not result[pymqi.CMQC.MQCA_Q_DESC].startswith(b'MQ'),
+                            'Found Queue with description {}'.format(result[pymqi.CMQC.MQCA_Q_DESC]))
+            self.assertTrue(pymqi.CMQC.MQCA_Q_DESC in result,
+                            'Attribute {} is not returned'.format(result[pymqi.CMQC.MQCA_Q_DESC]))
+
+    @data([], [b'One'], [b'One', b'Two', b'Three'])
+    def test_mqcfsl(self, value):
+        """Test MQCFSL PCF string list parameter.
+
+        Also uses MQCFST and MQCFIN as parameters
+        """
+        attrs = []
+        attrs.append(pymqi.CFST(Parameter=pymqi.CMQC.MQCA_NAMELIST_NAME,
+                                String='{}NAMELIST'.format(self.prefix).encode()))
+        attrs.append(pymqi.CFSL(Parameter=pymqi.CMQC.MQCA_NAMES,
+                                Strings=value))
+        attrs.append(pymqi.CFIN(Parameter=pymqi.CMQCFC.MQIACF_REPLACE,
+                                Value=pymqi.CMQCFC.MQRP_YES))
+
+        try:
+            self.pcf.MQCMD_CREATE_NAMELIST(attrs)
+        except Exception:  # pylint: disable=broad-except
+            self.fail('Exception occurs!')
+        else:
+            attrs = []
+            attrs.append(pymqi.CFST(Parameter=pymqi.CMQC.MQCA_NAMELIST_NAME,
+                                    String='{}NAMELIST'.format(self.prefix).encode()))
+            attrs.append(pymqi.CFIL(Parameter=pymqi.CMQCFC.MQIACF_NAMELIST_ATTRS,
+                                    Values=[pymqi.CMQC.MQCA_NAMES, pymqi.CMQC.MQIA_NAME_COUNT]))
+
+            results = self.pcf.MQCMD_INQUIRE_NAMELIST(attrs)
+
+            self.assertEqual(results[0][pymqi.CMQC.MQIA_NAME_COUNT], len(value))
 
@@ -40,9 +154,59 @@
 
-        args = {pymqi.CMQC.MQCA_Q_NAME: utils.py3str2bytes(queue_name),
-                pymqi.CMQC.MQIA_Q_TYPE: queue_type,
-                pymqi.CMQC.MQCA_Q_DESC: utils.py3str2bytes('PCF testing'),
-                pymqi.CMQCFC.MQIACF_REPLACE: pymqi.CMQCFC.MQRP_YES}
-        pcf = pymqi.PCFExecute(self.qmgr)
-        pcf.MQCMD_CREATE_Q(args)
-        pcf.disconnect
+            if results[0][pymqi.CMQC.MQIA_NAME_COUNT] > 0:
+                for item in results[0][pymqi.CMQC.MQCA_NAMES]:
+                    item = item.strip()
+                    self.assertTrue(item in value, '{} value not in values list'.format(item))
+                    value.remove(item)
+
+            attrs = []
+            attrs.append(pymqi.CFST(Parameter=pymqi.CMQC.MQCA_NAMELIST_NAME,
+                                    String='{}NAMELIST'.format(self.prefix).encode()))
+            self.pcf.MQCMD_DELETE_NAMELIST(attrs)
+
+
+    @data([], [1], [1, 2, 3, 4, 5])
+    def test_arbitrary_message_with_mqcfil(self, value):
+        """Test arbitrary message with MQCFIL."""
+        message = pymqi.CFH(Version=pymqi.CMQCFC.MQCFH_VERSION_1,
+                            Type=pymqi.CMQCFC.MQCFT_USER,
+                            ParameterCount=1).pack()
+        message = message + pymqi.CFIL(Parameter=1,
+                                       Values=value).pack()
+
+        queue = pymqi.Queue(self.qmgr, self.queue_name,
+                            pymqi.CMQC.MQOO_INPUT_AS_Q_DEF + pymqi.CMQC.MQOO_OUTPUT)
+
+        put_md = pymqi.MD(Format=pymqi.CMQC.MQFMT_PCF)
+        queue.put(message, put_md)
+
+        get_opts = pymqi.GMO(
+            Options=pymqi.CMQC.MQGMO_NO_SYNCPOINT + pymqi.CMQC.MQGMO_FAIL_IF_QUIESCING,
+            Version=pymqi.CMQC.MQGMO_VERSION_2,
+            MatchOptions=pymqi.CMQC.MQMO_MATCH_CORREL_ID)
+        get_md = pymqi.MD(MsgId=put_md.MsgId)  # pylint: disable=no-member
+        message = queue.get(None, get_md, get_opts)
+        queue.close()
+        message = pymqi.PCFExecute.unpack(message)
+
+        self.assertTrue(isinstance(message[0][1], list),
+                        'Returned value is not list: {}'.format(type(message[0][1])))
+
+        self.assertTrue(len(message[0][1]) == len(value), 'List length is different!')
+
+        for item in message[0][1]:
+            self.assertTrue(item in value, '{} value not in values list'.format(item))
+            value.remove(item)
+
+    def test_mqcfbs_old(self):
+        """Test byte string MQCFBS with old style."""
+        attrs = {
+            pymqi.CMQCFC.MQBACF_GENERIC_CONNECTION_ID: pymqi.ByteString(''),
+            pymqi.CMQCFC.MQIACF_CONN_INFO_TYPE: pymqi.CMQCFC.MQIACF_CONN_INFO_CONN,
+            pymqi.CMQCFC.MQIACF_CONNECTION_ATTRS: [pymqi.CMQCFC.MQIACF_ALL]
+        }
+        fltr = pymqi.Filter(pymqi.CMQC.MQIA_APPL_TYPE).equal(pymqi.CMQC.MQAT_USER)
+
+        results = self.pcf.MQCMD_INQUIRE_CONNECTION(attrs, [fltr])
+
+        self.assertGreater(len(results), 0)
 
@@ -48,4 +212,60 @@
 
-    def delete_queue(self, queue_name):
+    @data(pymqi.CMQCFC.MQIACF_ALL, [pymqi.CMQCFC.MQIACF_ALL],
+          pymqi.CMQC.MQCA_Q_DESC, [pymqi.CMQC.MQCA_Q_DESC],
+          [pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, pymqi.CMQC.MQCA_Q_DESC])
+    def test_object_filter_int_old_queue(self, value):
+        """Test object filter with integer attribute. Old style."""
+        attrs = {
+            pymqi.CMQC.MQCA_Q_NAME: b'*',
+            pymqi.CMQCFC.MQIACF_Q_ATTRS: value
+            }
+
+        filter_depth = pymqi.Filter(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH).greater(0)
+
+        results = self.pcf.MQCMD_INQUIRE_Q(attrs, [filter_depth])
+
+        self.assertTrue(results, 'Queue not found')
+        for result in results:
+            self.assertTrue(result[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH] > 0,
+                            'Found Queue with depth {}'.format(result[pymqi.CMQC.MQIA_CURRENT_Q_DEPTH]))
+
+    @skip('https://stackoverflow.com/questions/62250844/ibm-mq-pcf-parameters-order')
+    @data(pymqi.CMQCFC.MQIACF_ALL, [pymqi.CMQCFC.MQIACF_ALL],
+          pymqi.CMQCFC.MQCACH_DESC, [pymqi.CMQCFC.MQCACH_DESC],
+          [pymqi.CMQCFC.MQCACH_DESC, pymqi.CMQCFC.MQIACH_CHANNEL_TYPE])
+    def test_object_filter_int_old_channel(self, value):
+        """Test object filter with integer attribute. Old style."""
+        attrs = {
+            pymqi.CMQCFC.MQCACH_CHANNEL_NAME: b'*',
+            pymqi.CMQCFC.MQIACF_CHANNEL_ATTRS: value}
+
+        filter_type = pymqi.Filter(pymqi.CMQCFC.MQIACH_CHANNEL_TYPE).equal(pymqi.CMQC.MQCHT_SVRCONN)
+
+        results = self.pcf.MQCMD_INQUIRE_CHANNEL(attrs, [filter_type])
+
+        self.assertTrue(results, 'Channel not found')
+        for result in results:
+            self.assertTrue(result[pymqi.CMQCFC.MQIACH_CHANNEL_TYPE] == pymqi.CMQC.MQCHT_SVRCONN,
+                            'Found Channel with type {}'.format(result[pymqi.CMQCFC.MQIACH_CHANNEL_TYPE]))
+
+    def test_object_filter_str_old(self):
+        """Test object filter with string attribute. Old style."""
+        attrs = {
+            pymqi.CMQC.MQCA_Q_NAME: b'*',
+            pymqi.CMQCFC.MQIACF_Q_ATTRS: [pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, pymqi.CMQC.MQCA_Q_DESC]
+            }
+
+        filter_depth = pymqi.Filter(pymqi.CMQC.MQCA_Q_DESC).like(b'IBM MQ *')
+
+        results = self.pcf.MQCMD_INQUIRE_Q(attrs, [filter_depth])
+
+        self.assertTrue(results, 'Queue not found')
+        for result in results:
+            self.assertTrue(not result[pymqi.CMQC.MQCA_Q_DESC].startswith(b'MQ'),
+                            'Found Queue with description {}'.format(result[pymqi.CMQC.MQCA_Q_DESC]))
+
+    def test_disconnect(self):
+        """Test disconnect for PCF object."""
+        # pylint: disable=protected-access
 
         pcf = pymqi.PCFExecute(self.qmgr)
@@ -50,7 +270,3 @@
 
         pcf = pymqi.PCFExecute(self.qmgr)
-        args = {pymqi.CMQC.MQCA_Q_NAME: utils.py3str2bytes(queue_name),
-                pymqi.CMQCFC.MQIACF_PURGE: pymqi.CMQCFC.MQPO_YES}
-        pcf.MQCMD_DELETE_Q(args)
-        pcf.disconnect
 
@@ -56,8 +272,4 @@
 
-    def test_object_inquire_multiple_attributes(self):
-        attrs = {
-            pymqi.CMQC.MQCA_Q_NAME : utils.py3str2bytes(self.queue_name),
-            pymqi.CMQC.MQIA_Q_TYPE : pymqi.CMQC.MQQT_LOCAL,
-            pymqi.CMQCFC.MQIACF_Q_ATTRS : [pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, pymqi.CMQC.MQCA_Q_DESC]
-            }
+        self.assertTrue(pcf._reply_queue)
+        self.assertTrue(pcf._reply_queue_name)
 
@@ -63,14 +275,8 @@
 
-        pcf = pymqi.PCFExecute(self.qmgr)
-        results = pcf.MQCMD_INQUIRE_Q(attrs)
-        pcf.disconnect
-        
-        queue_inquired = False
-        for result in results:
-            if result.get(pymqi.CMQC.MQCA_Q_NAME).decode().strip() == self.queue_name:
-                if pymqi.CMQC.MQIA_CURRENT_Q_DEPTH in result and pymqi.CMQC.MQCA_Q_DESC in result:
-                    queue_inquired = True
-        
-        self.assertEqual(True, queue_inquired)
+        pcf.disconnect()
+
+        self.assertTrue(self.qmgr)
+        self.assertFalse(pcf._reply_queue)
+        self.assertFalse(pcf._reply_queue_name)
 
 if __name__ == "__main__":
@@ -75,3 +281,3 @@
 
 if __name__ == "__main__":
-    unittest.main()        
+    main(module="test_pcf")
diff --git a/code/tests/test_queue_manager.py b/code/tests/test_queue_manager.py
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS90ZXN0cy90ZXN0X3F1ZXVlX21hbmFnZXIucHk=..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS90ZXN0cy90ZXN0X3F1ZXVlX21hbmFnZXIucHk= 100644
--- a/code/tests/test_queue_manager.py
+++ b/code/tests/test_queue_manager.py
@@ -20,5 +20,5 @@
 import pymqi
 import pymqi.CMQC
 
-    
+
 class TestQueueManager(unittest.TestCase):
@@ -24,5 +24,5 @@
 class TestQueueManager(unittest.TestCase):
-    
+
     qm_name = config.MQ.QM.NAME
     channel = config.MQ.QM.CHANNEL
     host = config.MQ.QM.HOST
@@ -33,7 +33,7 @@
 
     user = config.MQ.QM.USER
     password = config.MQ.QM.PASSWORD
-    
+
     def test_init_none(self):
         qmgr = pymqi.QueueManager(None)
         self.assertFalse(qmgr.is_connected)
@@ -67,7 +67,7 @@
         qmgr.connect(self.qm_name)
         self.assertTrue(qmgr.is_connected)
         qmgr.disconnect()
-        
+
     def test_connect_tcp_client(self):
         qmgr = pymqi.QueueManager(None)
         qmgr.connect_tcp_client(
@@ -79,8 +79,7 @@
     def test_connect_tcp_client_conection_list(self):
         qmgr = pymqi.QueueManager(None)
         self.conn_info = '127.0.0.1(22),{0}'.format(self.conn_info)
-        #self.conn_info = '127.0.0.1(1314)'
         qmgr.connect_tcp_client(
             self.qm_name, pymqi.cd(), self.channel, self.conn_info, user=self.user,
             password=self.password)
         self.assertTrue(qmgr.is_connected)
@@ -83,8 +82,8 @@
         qmgr.connect_tcp_client(
             self.qm_name, pymqi.cd(), self.channel, self.conn_info, user=self.user,
             password=self.password)
         self.assertTrue(qmgr.is_connected)
-        qmgr.disconnect()        
+        qmgr.disconnect()
 
     # This test overlaps with
     # test_mq80.test_successful_connect_without_optional_credentials,
@@ -122,7 +121,7 @@
         handle = qmgr.get_handle()
         # assertIsInstance is available >= Python2.7
         self.assertTrue(isinstance(handle, int))
-        
+
     @unittest.skip('Not implemented yet')
     def test_begin(self):
         pass
@@ -155,5 +154,5 @@
         attribute = pymqi.CMQC.MQCA_Q_MGR_NAME
         expected_value = utils.py3str2bytes(self.qm_name)
         attribute_value = qmgr.inquire(attribute)
-        self.assertEqual(len(attribute_value), pymqi.CMQC.MQ_Q_MGR_NAME_LENGTH)  
+        self.assertEqual(len(attribute_value), pymqi.CMQC.MQ_Q_MGR_NAME_LENGTH)
         self.assertEqual(attribute_value.strip(), expected_value)
@@ -159,5 +158,5 @@
         self.assertEqual(attribute_value.strip(), expected_value)
-        
+
     def test_is_connected(self):
         """Makes sure the QueueManager's 'is_connected' property works as
         expected.
@@ -201,7 +200,7 @@
                     password)
 
                 eq_(qmgr.is_connected, expected)
-        
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/code/tests/test_setup.py b/code/tests/test_setup.py
index 6d0fe0104b09c65a734d6c3641189ba07196695d_Y29kZS90ZXN0cy90ZXN0X3NldHVwLnB5..6c07b79a3b2b7cd6590090fda544a6c4228a2666_Y29kZS90ZXN0cy90ZXN0X3NldHVwLnB5 100644
--- a/code/tests/test_setup.py
+++ b/code/tests/test_setup.py
@@ -1,5 +1,7 @@
 """Setup tests environment."""
 import os.path
-import unittest
+from unittest import TestCase  # noqa
+from unittest import main # pylint: disable=unused-import
+
 import pymqi
 
@@ -4,5 +6,5 @@
 import pymqi
 
-import config
-import utils
+import config  # noqa
+import utils  # noqa
 
@@ -8,5 +10,6 @@
 
-class Tests(unittest.TestCase):
+
+class Tests(TestCase):
     """Setup and tearsdown tests environment."""
 
     version = '0000000'
@@ -19,4 +22,6 @@
     user = ''
     password = ''
 
+    prefix = ''
+
     qmgr = None
@@ -22,6 +27,6 @@
     qmgr = None
-    
+
 
     @classmethod
     def setUpClass(cls):
         """Initialize test environment."""
@@ -24,8 +29,8 @@
 
     @classmethod
     def setUpClass(cls):
         """Initialize test environment."""
-        cls.prefix = os.environ.get('PYMQI_TEST_OBJECT_PREFIX', '')
+        cls.prefix = os.environ.get('PYMQI_TEST_OBJECT_PREFIX', 'PYMQI.')
 
         # max length of queue names is 48 characters
         cls.queue_name = "{prefix}MSG.QUEUE".format(prefix=config.MQ.QUEUE.PREFIX)
@@ -39,7 +44,11 @@
         cls.conn_info = "{0}({1})".format(cls.host, cls.port)
 
         cls.qmgr = pymqi.QueueManager(None)
-        cls.qmgr.connectTCPClient(cls.queue_manager, pymqi.CD(), cls.channel, cls.conn_info, cls.user, cls.password)
+        try:
+            cls.qmgr.connectTCPClient(cls.queue_manager, pymqi.CD(), cls.channel, cls.conn_info, cls.user, cls.password)
+        except pymqi.MQMIError as ex:
+            if ex.comp == pymqi.CMQC.MQCC_FAILED:
+                raise ex
 
         cls.version = cls.inquire_qmgr_version().decode()
 
@@ -49,11 +58,7 @@
         cls.qmgr.disconnect()
 
     def setUp(self):
-        """Setup tests environmet.
-        Configuration for setup provided by config.py
-        Creates connection `self.qmgr` to Queue Manager `self.queue_manager`
-        and creates queue `self.queue_name`
-        """
+        """Set up tesing environment."""
 
     def tearDown(self):
         """Clear test environment."""
@@ -57,6 +62,6 @@
 
     def tearDown(self):
         """Clear test environment."""
-    
+
     @classmethod
     def inquire_qmgr_version(cls):
@@ -61,5 +66,6 @@
     @classmethod
     def inquire_qmgr_version(cls):
+        """Inqure Queue Manager version."""
         return cls.qmgr.inquire(pymqi.CMQC.MQCA_VERSION)
 
     def create_queue(self, queue_name, max_depth=5000, args=None):
@@ -63,6 +69,7 @@
         return cls.qmgr.inquire(pymqi.CMQC.MQCA_VERSION)
 
     def create_queue(self, queue_name, max_depth=5000, args=None):
+        """Create queue."""
         if args:
             args[pymqi.CMQC.MQCA_Q_NAME] = utils.py3str2bytes(queue_name)
         else:
@@ -74,7 +81,8 @@
         pcf.MQCMD_CREATE_Q(args)
 
     def delete_queue(self, queue_name):
+        """Delete queue."""
         pcf = pymqi.PCFExecute(self.qmgr)
         args = {pymqi.CMQC.MQCA_Q_NAME: utils.py3str2bytes(queue_name),
                 pymqi.CMQCFC.MQIACF_PURGE: pymqi.CMQCFC.MQPO_YES}
         pcf.MQCMD_DELETE_Q(args)
@@ -77,6 +85,6 @@
         pcf = pymqi.PCFExecute(self.qmgr)
         args = {pymqi.CMQC.MQCA_Q_NAME: utils.py3str2bytes(queue_name),
                 pymqi.CMQCFC.MQIACF_PURGE: pymqi.CMQCFC.MQPO_YES}
         pcf.MQCMD_DELETE_Q(args)
-    
+
     def create_channel(self, channel_name, args=None):
@@ -82,4 +90,5 @@
     def create_channel(self, channel_name, args=None):
+        """Create channle."""
         if args:
             args[pymqi.CMQCFC.MQCACH_CHANNEL_NAME] = utils.py3str2bytes(channel_name)
         else:
@@ -90,8 +99,9 @@
         pcf.MQCMD_CREATE_CHANNEL(args)
 
     def delete_channel(self, channel_name):
+        """Delete channel."""
         pcf = pymqi.PCFExecute(self.qmgr)
         args = {pymqi.CMQCFC.MQCACH_CHANNEL_NAME: utils.py3str2bytes(channel_name)}
         pcf.MQCMD_DELETE_CHANNEL(args)
 
     def create_auth_rec(self, args):
@@ -93,7 +103,8 @@
         pcf = pymqi.PCFExecute(self.qmgr)
         args = {pymqi.CMQCFC.MQCACH_CHANNEL_NAME: utils.py3str2bytes(channel_name)}
         pcf.MQCMD_DELETE_CHANNEL(args)
 
     def create_auth_rec(self, args):
+        """Create authentication recoed."""
         pcf = pymqi.PCFExecute(self.qmgr)
         pcf.MQCMD_SET_CHLAUTH_REC(args)
@@ -98,4 +109,4 @@
         pcf = pymqi.PCFExecute(self.qmgr)
         pcf.MQCMD_SET_CHLAUTH_REC(args)
-    
+
     def delete_auth_rec(self, args):
@@ -101,3 +112,4 @@
     def delete_auth_rec(self, args):
+        """Delete authentication recoed."""
         pcf = pymqi.PCFExecute(self.qmgr)
         pcf.MQCMD_SET_CHLAUTH_REC(args)
@@ -102,5 +114,5 @@
         pcf = pymqi.PCFExecute(self.qmgr)
         pcf.MQCMD_SET_CHLAUTH_REC(args)
-    
+
     @classmethod
     def edit_qmgr(cls, args):
@@ -105,5 +117,6 @@
     @classmethod
     def edit_qmgr(cls, args):
+        """Edit connected Queue Manager."""
         pcf = pymqi.PCFExecute(cls.qmgr)
         pcf.MQCMD_CHANGE_Q_MGR(args)
 
diff --git a/docs/examples.rst b/docs/examples.rst
index 6d0fe0104b09c65a734d6c3641189ba07196695d_ZG9jcy9leGFtcGxlcy5yc3Q=..6c07b79a3b2b7cd6590090fda544a6c4228a2666_ZG9jcy9leGFtcGxlcy5yc3Q= 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -1278,7 +1278,7 @@
     filter1 = pymqi.Filter(CMQC.MQCA_Q_DESC).like('IBM MQ *')
     filter2 = pymqi.Filter(CMQC.MQIA_CURRENT_Q_DEPTH).greater(2)
 
-    result = pcf.MQCMD_INQUIRE_Q(attrs, [f1, f2])
+    result = pcf.MQCMD_INQUIRE_Q(attrs, [filter1, filter2])
 
     logging.info('Result is %s', result)