Index: server/lib/gutenbach/ipp/__init__.py
===================================================================
--- server/lib/gutenbach/ipp/__init__.py	(revision 71bfce0b333b007df44decc7e73d62251f97b911)
+++ server/lib/gutenbach/ipp/__init__.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
@@ -3,7 +3,8 @@
 from request import Request
 from value import Value
-from constants import Tags
+from constants import Tags, StatusCodes
 import operations as ops
 import exceptions as errors
 
-__all__ = ['Attribute', 'AttributeGroup', 'Request', 'Value', 'Tags', 'ops', 'errors']
+__all__ = ['Attribute', 'AttributeGroup', 'Request', 'Value',
+           'Tags', 'StatusCodes', 'ops', 'errors']
Index: server/lib/gutenbach/ipp/attribute.py
===================================================================
--- server/lib/gutenbach/ipp/attribute.py	(revision d04a6891fc6c9f9ce772732907214ccd85485868)
+++ server/lib/gutenbach/ipp/attribute.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
@@ -66,5 +66,5 @@
         for value in values:
             assert isinstance(value, Value), \
-                   "Value %r must be of type Value" % (value)
+                   "Value %s must be of type Value" % (value,)
 
         self.name = name
@@ -100,8 +100,8 @@
             logger.debug("dumping name : %s" % self.name)
             logger.debug("dumping value_length : %i" % value_length)
-            logger.debug("dumping value : %s" % v.value)
+            logger.debug("dumping value (0x%x): %s" % (v.tag, v.value))
 
             # the value tag in binary
-            value_tag_bin = struct.pack('>b', v.value_tag)
+            tag_bin = struct.pack('>b', v.tag)
 
             # the name length in binary
@@ -115,5 +115,5 @@
 
             if i == 0:
-                values.append(''.join([value_tag_bin,
+                values.append(''.join([tag_bin,
                                        name_length_bin,
                                        name_bin,
@@ -121,5 +121,5 @@
                                        value_bin]))
             else:
-                values.append(''.join([value_tag_bin,
+                values.append(''.join([tag_bin,
                                        name_length_bin,
                                        value_length_bin,
Index: server/lib/gutenbach/ipp/exceptions.py
===================================================================
--- server/lib/gutenbach/ipp/exceptions.py	(revision 5b3a81ea173993f82b4e9827993e20fdbc9de561)
+++ server/lib/gutenbach/ipp/exceptions.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
@@ -25,38 +25,38 @@
 
 class BadRequest(IPPClientException):
-    ipp_error_code = ErrorCodes.BAD_REQUEST)
+    ipp_error_code = ErrorCodes.BAD_REQUEST
 
 class Forbidden(IPPClientException):
-    ipp_error_code = ErrorCodes.FORBIDDEN)
+    ipp_error_code = ErrorCodes.FORBIDDEN
 
 class NotAuthenticated(IPPClientException):
-    ipp_error_code = ErrorCodes.NOT_AUTHENTICATED)
+    ipp_error_code = ErrorCodes.NOT_AUTHENTICATED
 
 class NotAuthorized(IPPClientException):
-    ipp_error_code = ErrorCodes.NOT_AUTHORIZED)
+    ipp_error_code = ErrorCodes.NOT_AUTHORIZED
 
 class NotPossible(IPPClientException):
-    ipp_error_code = ErrorCodes.NOT_POSSIBLE)
+    ipp_error_code = ErrorCodes.NOT_POSSIBLE
 
 class Timeout(IPPClientException):
-    ipp_error_code = ErrorCodes.TIMEOUT)
+    ipp_error_code = ErrorCodes.TIMEOUT
 
 class NotFound(IPPClientException):
-    ipp_error_code = ErrorCodes.NOT_FOUND)
+    ipp_error_code = ErrorCodes.NOT_FOUND
 
 class Gone(IPPClientException):
-    ipp_error_code = ErrorCodes.GONE)
+    ipp_error_code = ErrorCodes.GONE
 
 class RequestEntity(IPPClientException):
-    ipp_error_code = ErrorCodes.REQUEST_ENTITY)
+    ipp_error_code = ErrorCodes.REQUEST_ENTITY
 
 class RequestValue(IPPClientException):
-    ipp_error_code = ErrorCodes.REQUEST_VALUE)
+    ipp_error_code = ErrorCodes.REQUEST_VALUE
 
 class DocumentFormatNotSupported(IPPClientException):
-    ipp_error_code = ErrorCodes.DOCUMENT_FORMAT)
+    ipp_error_code = ErrorCodes.DOCUMENT_FORMAT
 
 class Attributes(IPPClientException):
-    ipp_error_code = ErrorCodes.ATTRIBUTES)
+    ipp_error_code = ErrorCodes.ATTRIBUTES
 
     def __init__(self, message, attrs):
@@ -68,71 +68,71 @@
 
 class UriSchemeNotSupported(IPPClientException):
-    ipp_error_code = ErrorCodes.URI_SCHEME)
+    ipp_error_code = ErrorCodes.URI_SCHEME
 
 class CharsetNotSupported(IPPClientException):
-    ipp_error_code = ErrorCodes.CHARSET)
+    ipp_error_code = ErrorCodes.CHARSET
 
 class Conflict(IPPClientException):
-    ipp_error_code = ErrorCodes.CONFLICT)
+    ipp_error_code = ErrorCodes.CONFLICT
 
 class CompressionNotSupported(IPPClientException):
-    ipp_error_code = ErrorCodes.COMPRESSION_NOT_SUPPORTED)
+    ipp_error_code = ErrorCodes.COMPRESSION_NOT_SUPPORTED
 
 class CompressionError(IPPClientException):
-    ipp_error_code = ErrorCodes.COMPRESSION_ERROR)
+    ipp_error_code = ErrorCodes.COMPRESSION_ERROR
 
 class DocumentFormatError(IPPClientException):
-    ipp_error_code = ErrorCodes.DOCUMENT_FORMAT_ERROR)
+    ipp_error_code = ErrorCodes.DOCUMENT_FORMAT_ERROR
 
 class DocumentAccessError(IPPClientException):
-    ipp_error_code = ErrorCodes.DOCUMENT_ACCESS_ERROR)
+    ipp_error_code = ErrorCodes.DOCUMENT_ACCESS_ERROR
 
 class AttributesNotSettable(IPPClientException):
-    ipp_error_code = ErrorCodes.ATTRIBUTES_NOT_SETTABLE)
+    ipp_error_code = ErrorCodes.ATTRIBUTES_NOT_SETTABLE
 
 class IgnoredAllSubscriptions(IPPClientException):
-    ipp_error_code = ErrorCodes.IGNORED_ALL_SUBSCRIPTIONS)
+    ipp_error_code = ErrorCodes.IGNORED_ALL_SUBSCRIPTIONS
 
 class TooManySubscriptions(IPPClientException):
-    ipp_error_code = ErrorCodes.TOO_MANY_SUBSCRIPTIONS)
+    ipp_error_code = ErrorCodes.TOO_MANY_SUBSCRIPTIONS
 
 class IgnoredAllNotifications(IPPClientException):
-    ipp_error_code = ErrorCodes.IGNORED_ALL_NOTIFICATIONS)
+    ipp_error_code = ErrorCodes.IGNORED_ALL_NOTIFICATIONS
 
 class PrintSupportFileNotFound(IPPClientException):
-    ipp_error_code = ErrorCodes.PRINT_SUPPORT_FILE_NOT_FOUND)
+    ipp_error_code = ErrorCodes.PRINT_SUPPORT_FILE_NOT_FOUND
 
 ### Server error codes
 
 class InternalError(IPPServerException):
-    ipp_error_code = ErrorCodes.INTERNAL_ERROR)
+    ipp_error_code = ErrorCodes.INTERNAL_ERROR
 
 class OperationNotSupported(IPPServerException):
-    ipp_error_code = ErrorCodes.OPERATION_NOT_SUPPORTED)
+    ipp_error_code = ErrorCodes.OPERATION_NOT_SUPPORTED
 
 class ServiceUnavailable(IPPServerException):
-    ipp_error_code = ErrorCodes.SERVICE_UNAVAILABLE)
+    ipp_error_code = ErrorCodes.SERVICE_UNAVAILABLE
 
 class VersionNotSupported(IPPServerException):
-    ipp_error_code = ErrorCodes.VERSION_NOT_SUPPORTED)
+    ipp_error_code = ErrorCodes.VERSION_NOT_SUPPORTED
 
 class DeviceError(IPPServerException):
-    ipp_error_code = ErrorCodes.DEVICE_ERROR)
+    ipp_error_code = ErrorCodes.DEVICE_ERROR
 
 class TemporaryError(IPPServerException):
-    ipp_error_code = ErrorCodes.TEMPORARY_ERROR)
+    ipp_error_code = ErrorCodes.TEMPORARY_ERROR
 
 class NotAccepting(IPPServerException):
-    ipp_error_code = ErrorCodes.NOT_ACCEPTING)
+    ipp_error_code = ErrorCodes.NOT_ACCEPTING
 
 class PrinterBusy(IPPServerException):
-    ipp_error_code = ErrorCodes.PRINTER_BUSY)
+    ipp_error_code = ErrorCodes.PRINTER_BUSY
 
 class ErrorJobCancelled(IPPServerException):
-    ipp_error_code = ErrorCodes.ERROR_JOB_CANCELLED)
+    ipp_error_code = ErrorCodes.ERROR_JOB_CANCELLED
 
 class MultipleJobsNotSupported(IPPServerException):
-    ipp_error_code = ErrorCodes.MULTIPLE_JOBS_NOT_SUPPORTED)
+    ipp_error_code = ErrorCodes.MULTIPLE_JOBS_NOT_SUPPORTED
 
 class PrinterIsDeactivated(IPPServerException):
-    ipp_error_code = ErrorCodes.PRINTER_IS_DEACTIVATED)
+    ipp_error_code = ErrorCodes.PRINTER_IS_DEACTIVATED
Index: server/lib/gutenbach/ipp/operations.py
===================================================================
--- server/lib/gutenbach/ipp/operations.py	(revision 71bfce0b333b007df44decc7e73d62251f97b911)
+++ server/lib/gutenbach/ipp/operations.py	(revision f6c6897421d09df51b72b4539328adec41072c46)
@@ -3,8 +3,6 @@
 from .attributegroup import AttributeGroup
 from .request import Request
-from .constants import AttributeTags, operations_attribute_value_tags
+from .constants import AttributeTags, StatusCodes, operations_attribute_value_tags
 import exceptions as err
-
-from collections import OrderedDictionary as odict
 
 def verify_operations(request):
@@ -43,5 +41,4 @@
 
     # check charset
-    charset attribute
     charset_attr = op_attrs.attributes[0]
     if charset_attr.name != 'attributes-charset':
@@ -73,5 +70,5 @@
     if natlang_value.tag != operations_attribute_value_tags['attributes-natural-language']:
         raise err.BadRequest(
-            "Natural language value does not have NATURAL_LANGUAGE tag: 0x%x" natlang_value.tag)
+            "Natural language value does not have NATURAL_LANGUAGE tag: 0x%x" % natlang_value.tag)
     if natlang_value.value != 'en-us':
         raise err.Attributes(
@@ -115,14 +112,14 @@
     # Operation attributes -- typically the same for any request
     attributes = [
-        ipp.Attribute(
+        Attribute(
             'attributes-charset',
-            [(operations_attribute_value_tags['attributes-charset'], 'utf-8')]),
-        ipp.Attribute(
+            [Value(operations_attribute_value_tags['attributes-charset'], 'utf-8')]),
+        Attribute(
             'attributes-natural-language',
-            [(operations_attribute_value_tags['attributes-natural-language'], 'en-us')])
+            [Value(operations_attribute_value_tags['attributes-natural-language'], 'en-us')])
         ]
     # Put the operation attributes in a group
-    attribute_group = ipp.AttributeGroup(
-        const.AttributeTags.OPERATION,
+    attribute_group = AttributeGroup(
+        AttributeTags.OPERATION,
         attributes)
 
@@ -131,8 +128,8 @@
     response_kwargs = {}
     response_kwargs['version']          = request.version
-    response_kwargs['operation_id']     = const.StatusCodes.OK
+    response_kwargs['operation_id']     = StatusCodes.OK
     response_kwargs['request_id']       = request.request_id
     response_kwargs['attribute_groups'] = [attribute_group]
-    response = ipp.Request(**response_kwargs)
+    response = Request(**response_kwargs)
 
     return response
@@ -168,8 +165,8 @@
             if 'which-jobs' or 'my-jobs' constrain which jobs are
             returned. The limit is a 'stateless limit' in that if
-            the value supplied by the client is ’N’, then only the
-            first ’N’ jobs are returned in the Get-Jobs Response.
-            There is no mechanism to allow for the next ’M’ jobs
-            after the first ’N’ jobs. If the client does not
+            the value supplied by the client is 'N', then only the
+            first 'N' jobs are returned in the Get-Jobs Response.
+            There is no mechanism to allow for the next 'M' jobs
+            after the first 'N' jobs. If the client does not
             supply this attribute, the Printer object responds
             with all applicable jobs.
@@ -185,5 +182,5 @@
             the client does not supply this attribute, the Printer
             MUST respond as if the client had supplied this
-            attribute with two values: ’job-uri’ and ’job-id’.
+            attribute with two values: 'job-uri' and 'job-id'.
         'which-jobs' (type2 keyword):
             The client OPTIONALLY supplies this attribute. The
@@ -191,22 +188,22 @@
             indicates which Job objects MUST be returned by the
             Printer object. The values for this attribute are:
-             - ’completed’: This includes any Job object whose
-               state is ’completed’, ’canceled’, or ’aborted’.
-             - ’not-completed’: This includes any Job object whose
-               state is ’pending’, ’processing’,
-               ’processing-stopped’, or ’pending-held’.
+             - 'completed': This includes any Job object whose
+               state is 'completed', 'canceled', or 'aborted'.
+             - 'not-completed': This includes any Job object whose
+               state is 'pending', 'processing',
+               'processing-stopped', or 'pending-held'.
             A Printer object MUST support both values. However, if
             the implementation does not keep jobs in the
-            ’completed’, ’canceled’, and ’aborted’ states, then it
-            returns no jobs when the ’completed’ value is
+            'completed', 'canceled', and 'aborted' states, then it
+            returns no jobs when the 'completed' value is
             supplied.  If a client supplies some other value, the
             Printer object MUST copy the attribute and the
             unsupported value to the Unsupported Attributes
             response group, reject the request, and return the
-            ’client-error-attributes-or-values-not-supported’
+            'client-error-attributes-or-values-not-supported'
             status code.  If the client does not supply this
             attribute, the Printer object MUST respond as if the
             client had supplied the attribute with a value of
-            ’not-completed’.
+            'not-completed'.
         'my-jobs' (boolean):
             The client OPTIONALLY supplies this attribute. The
@@ -218,5 +215,5 @@
             attribute, the Printer object MUST respond as if the
             client had supplied the attribute with a value of
-            ’false’, i.e., jobs from all users. The means for
+            'false', i.e., jobs from all users. The means for
             authenticating the requesting user and matching the
             jobs is described in section 8.
@@ -268,7 +265,7 @@
     response returns 0 jobs because there are no jobs matching the
     criteria, and the request would have returned 1 or more jobs
-    with a status code of ’successful-ok’ if there had been jobs
+    with a status code of 'successful-ok' if there had been jobs
     matching the criteria, then the status code for 0 jobs MUST be
-    ’successful-ok’.
+    'successful-ok'.
 
     Group 1: Operation Attributes
@@ -293,5 +290,5 @@
         referenced in the 'requested-attributes' operation
         attribute and that attribute included group names, such as
-        ’all’, the unsupported attributes MUST NOT include
+        'all', the unsupported attributes MUST NOT include
         attributes described in the standard but not supported by
         the implementation.
@@ -306,5 +303,5 @@
         job (job originating user) or not (see section
         8). However, the Printer object MUST respond with the
-        ’unknown’ value for any supported attribute (including all
+        'unknown' value for any supported attribute (including all
         REQUIRED attributes) for which the Printer object does not
         know the value, unless it would violate the security
@@ -313,11 +310,11 @@
 
         Jobs are returned in the following order:
-        - If the client requests all ’completed’ Jobs (Jobs in the
-          ’completed’, ’aborted’, or ’canceled’ states), then the
+        - If the client requests all 'completed' Jobs (Jobs in the
+          'completed', 'aborted', or 'canceled' states), then the
           Jobs are returned newest to oldest (with respect to
           actual completion time)
-        - If the client requests all ’not-completed’ Jobs (Jobs in
-          the ’pending’, ’processing’, ’pending-held’, and
-          ’processing- stopped’ states), then Jobs are returned in
+        - If the client requests all 'not-completed' Jobs (Jobs in
+          the 'pending', 'processing', 'pending-held', and
+          'processing- stopped' states), then Jobs are returned in
           relative chronological order of expected time to
           complete (based on whatever scheduling algorithm is
