Index: server/lib/TODO
===================================================================
--- server/lib/TODO	(revision 20f736075fdbd842e82cd31308ab95d40222fdb3)
+++ server/lib/TODO	(revision 56fd535705c771a6dbbef58e877f665f42658e6d)
@@ -4,4 +4,5 @@
 
 - finish implementing a bunch of the IPP handlers
+     [ ] print job
      [ ] validate job
      [ ] pause printer
@@ -15,15 +16,16 @@
 
 - add support in printer.py for:
+     [ ] print job
      [ ] validate job
      [ ] pause printer
      [ ] resume printer
-     [ ] set printer attributes
-     [ ] send uri
-     [ ] set job attributes
-     [ ] restart job
-     [ ] promote job
+     [\] set printer attributes
+     [\] send uri
+     [\] set job attributes
+     [X] restart job
+     [\] promote job
 
 - add support in job.py for:
-     [ ] restart job
+     [X] restart job
 
 - finish test cases for printer.py
@@ -52,4 +54,5 @@
    - local streaming
    - generic streaming
+   - zephyr control (e.g. youtube link)
 
 Tickets that should be fixed by this new version:
Index: server/lib/gutenbach/server/job.py
===================================================================
--- server/lib/gutenbach/server/job.py	(revision cb0195f6baef36266d7ee28df880e982d563fe35)
+++ server/lib/gutenbach/server/job.py	(revision 92253512a365e2c69f963b7b11d480cc2a48133b)
@@ -383,4 +383,20 @@
 
     def restart(self):
-        # XXX: Todo
-        pass
+        """Non-blocking restart.  Job must be finished (see
+        'GutenbachJob.is_done'), and will be ready to be played (see
+        'GutenbachJob.is_ready') if this method is successful.
+
+        Raises
+        ------
+        InvalidJobStateException
+            If the job is not done.
+
+        """
+
+        if not self.is_done:
+            raise errors.InvalidJobStateException(self.state)
+
+        logger.debug("restarting job %d" % (self.id, self.document))
+
+        self._why_done = None
+        self.spool(self.document)
Index: server/lib/gutenbach/server/printer.py
===================================================================
--- server/lib/gutenbach/server/printer.py	(revision fa3e2c628aa908bb9ab4b03f34704a58ae1ef96e)
+++ server/lib/gutenbach/server/printer.py	(revision 92253512a365e2c69f963b7b11d480cc2a48133b)
@@ -184,28 +184,49 @@
     def printer_uri_supported(self):
         return ipp.PrinterUriSupported(self.uri)
+    @printer_uri_supported.setter
+    def printer_uri_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-uri-supported")
 
     @property
     def uri_authentication_supported(self):
         return ipp.UriAuthenticationSupported("none")
+    @uri_authentication_supported.setter
+    def uri_authentication_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("uri-authentication-supported")
 
     @property
     def uri_security_supported(self):
         return ipp.UriSecuritySupported("none")
+    @uri_security_supported.setter
+    def uri_security_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("uri-security-supported")
 
     @property
     def printer_name(self):
         return ipp.PrinterName(self.name)
+    @printer_name.setter
+    def printer_name(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-name")
 
     @property
     def printer_state(self):
         return ipp.PrinterState(self.state)
+    @printer_state.setter
+    def printer_state(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-state")
 
     @property
     def printer_state_reasons(self):
         return ipp.PrinterStateReasons("none")
+    @printer_state_reasons.setter
+    def printer_state_reasons(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-state-reasons")
 
     @property
     def ipp_versions_supported(self):
         return ipp.IppVersionsSupported(*self.config['ipp-versions'])
+    @ipp_versions_supported.setter
+    def ipp_versions_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("ipp-versions-supported")
 
     # XXX: We should query ourself for the supported operations
@@ -213,56 +234,98 @@
     def operations_supported(self):
         return ipp.OperationsSupported(ipp.OperationCodes.GET_JOBS)
+    @operations_supported.setter
+    def operations_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("operations-supported")
 
     @property
     def charset_configured(self):
-        return ipp.CharsetConfigured("utf-8")
-
+        return ipp.CharsetConfigured("utf-8") # XXX
+    @charset_configured.setter
+    def charset_configured(self, val):
+        raise ipp.errors.AttributesNotSettable("charset-configured")
+        
     @property
     def charset_supported(self):
-        return ipp.CharsetSupported("utf-8")
+        return ipp.CharsetSupported("utf-8") # XXX
+    @charset_supported.setter
+    def charset_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("charset-supported")
 
     @property
     def natural_language_configured(self):
         return ipp.NaturalLanguageConfigured("en-us")
+    @natural_language_configured.setter
+    def natural_language_configured(self, val):
+        raise ipp.errors.AttributesNotSettable("natural-language-configured")
 
     @property
     def generated_natural_language_supported(self):
         return ipp.GeneratedNaturalLanguageSupported("en-us")
+    @generated_natural_language_supported.setter
+    def generated_natural_language_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("generated-natural-language-supported")
 
     @property
     def document_format_default(self):
         return ipp.DocumentFormatDefault("application/octet-stream")
+    @document_format_default.setter
+    def document_format_default(self, val):
+        raise ipp.errors.AttributesNotSettable("document-format-default")
 
     @property
     def document_format_supported(self):
         return ipp.DocumentFormatSupported("application/octet-stream", "audio/mp3")
+    @document_format_supported.setter
+    def document_format_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("document-format-supported")
 
     @property
     def printer_is_accepting_jobs(self):
         return ipp.PrinterIsAcceptingJobs(True)
+    @printer_is_accepting_jobs.setter
+    def printer_is_accepting_jobs(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-is-accepting-jobs")
 
     @property
     def queued_job_count(self):
         return ipp.QueuedJobCount(len(self.active_jobs))
+    @queued_job_count.setter
+    def queued_job_count(self, val):
+        raise ipp.errors.AttributesNotSettable("queued-job-count")
 
     @property
     def pdl_override_supported(self):
         return ipp.PdlOverrideSupported("not-attempted")
+    @pdl_override_supported.setter
+    def pdl_override_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("pdl-override-supported")
 
     @property
     def printer_up_time(self):
         return ipp.PrinterUpTime(int(time.time()) - self.time_created)
+    @printer_up_time.setter
+    def printer_up_time(self, val):
+        raise ipp.errors.AttributesNotSettable("printer-up-time")
 
     @property
     def compression_supported(self):
         return ipp.CompressionSupported("none")
+    @compression_supported.setter
+    def compression_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("compression-supported")
 
     @property
     def multiple_operation_time_out(self):
         return ipp.MultipleOperationTimeOut(240)
+    @multiple_operation_time_out.setter
+    def multiple_operation_time_out(self, val):
+        raise ipp.errors.AttributesNotSettable("multiple-operation-time-out")
 
     @property
     def multiple_document_jobs_supported(self):
         return ipp.MultipleDocumentJobsSupported(False)
+    @multiple_document_jobs_supported.setter
+    def multiple_document_jobs_supported(self, val):
+        raise ipp.errors.AttributesNotSettable("multiple-document-jobs-supported")
 
     ######################################################################
@@ -389,6 +452,10 @@
         return attributes
 
-    def set_printer_attributes(self):
-        pass
+    def set_printer_attributes(self, job_id, attributes):
+        for attr in attributes:
+            try:
+                setattr(self, attr, attributes[attr])
+            except AttributeError:
+                raise ipp.errors.ClientErrorAttributes
 
     def cancel_job(self, job_id, requesting_user_name=None):
@@ -408,6 +475,12 @@
         job.spool(document)
 
-    def send_uri(self):
-        pass
+    def send_uri(self, job_id, document_uri, document_name=None,
+                 document_format=None, document_natural_language=None,
+                 requesting_user_name=None, compression=None,
+                 last_document=None):
+        job = self.get_job(job_id)
+        # XXX: need to validate URI
+        # XXX: need to deal with the URI stream?
+        #job.spool_uri(document_uri)
 
     def get_job_attributes(self, job_id, requested_attributes=None):
@@ -422,10 +495,32 @@
         return attributes
 
-    def set_job_attributes(self):
-        pass
-
-    def restart_job(self):
-        pass
-
-    def promote_job(self):
-        pass
+    def set_job_attributes(self, job_id, attributes):
+        job = self.get_job(job_id)
+        for attr in attributes:
+            if attr in ("job-id", "job-k-octets", "job-state", "job-printer-uri"):
+                raise ipp.errors.ClientErrorAttributesNotSettable(attr)
+            elif attr == "job-name":
+                job.name = attributes[attr]
+            elif attr == "job-originating-user-name":
+                job.creator = attributes[attr] # XXX: do we want this?
+                
+    def restart_job(self, job_id, requesting_user_name=None):
+        job = self.get_job(job_id)
+        try:
+            job.restart()
+        except InvalidJobStateException:
+            # XXX
+            raise ipp.errors.ClientErrorNotPossible
+
+        with self.lock:
+            self.finished_jobs.remove(job_id)
+            self.pending_jobs.append(job_id)
+
+    def promote_job(self, job_id, requesting_user_name=None):
+        # According to RFC 3998, we need to put the job at the front
+        # of the queue (so that when the currently playing job
+        # completes, this one will go next
+        
+        job = self.get_job(job_id)
+        job.priority = 1 # XXX we need to actually do something
+                         # correct here
Index: server/lib/gutenbach/server/requests.py
===================================================================
--- server/lib/gutenbach/server/requests.py	(revision d994f158577355683c66a639ea8dbfcaf02864e7)
+++ server/lib/gutenbach/server/requests.py	(revision c1dc25fddcb3a5bee35914c03bc580615b1263cc)
@@ -268,4 +268,39 @@
     @handler_for(ipp.OperationCodes.PRINT_URI)
     def print_uri(self, request, response):
+        """3.2.2 Print-URI Operation
+
+        This OPTIONAL operation is identical to the Print-Job operation
+        (section 3.2.1) except that a client supplies a URI reference to the
+        document data using the 'document-uri' (uri) operation attribute (in
+        Group 1) rather than including the document data itself.  Before
+        returning the response, the Printer MUST validate that the Printer
+        supports the retrieval method (e.g., http, ftp, etc.) implied by the
+        URI, and MUST check for valid URI syntax.  If the client-supplied URI
+        scheme is not supported, i.e. the value is not in the Printer
+        object's 'referenced-uri-scheme-supported' attribute, the Printer
+        object MUST reject the request and return the 'client-error-uri-
+        scheme-not-supported' status code.
+
+        The IPP Printer MAY validate the accessibility of the document as
+        part of the operation or subsequently.  If the Printer determines an
+        accessibility problem before returning an operation response, it
+        rejects the request and returns the 'client-error-document-access-
+        error' status code.  The Printer MAY also return a specific document
+        access error code using the 'document-access-error' operation
+        attribute (see section 3.1.6.4).
+
+        If the Printer determines this document accessibility problem after
+        accepting the request and returning an operation response with one
+        of the successful status codes, the Printer adds the
+        'document-access- error' value to the job's 'job-state-reasons'
+        attribute and MAY populate the job's 'job-document-access-errors'
+        Job Description attribute (see section 4.3.11).  See The
+        Implementer's Guide [IPP- IIG] for suggested additional checks.
+                                                                              
+        If the Printer object supports this operation, it MUST support the
+        'reference-uri-schemes-supported' Printer attribute (see section 4.4.27).
+
+        It is up to the IPP object to interpret the URI and subsequently
+        'pull' the document from the source referenced by the URI string."""
         raise ipp.errors.ServerErrorOperationNotSupported
 
@@ -364,8 +399,170 @@
     @handler_for(ipp.OperationCodes.PAUSE_PRINTER)
     def pause_printer(self, request, response):
+        """
+            3.2.7 Pause-Printer Operation
+
+            This OPTIONAL operation allows a client to stop the Printer object
+            from scheduling jobs on all its devices.  Depending on
+            implementation, the Pause-Printer operation MAY also stop the Printer
+            from processing the current job or jobs.  Any job that is currently
+            being printed is either stopped as soon as the implementation permits
+            or is completed, depending on implementation.  The Printer object
+            MUST still accept create operations to create new jobs, but MUST
+            prevent any jobs from entering the 'processing' state.
+
+            If the Pause-Printer operation is supported, then the Resume-Printer
+            operation MUST be supported, and vice-versa.
+
+            The IPP Printer stops the current job(s) on its device(s) that were
+            in the 'processing' or 'processing-stopped' states as soon as the
+            implementation permits.  If the implementation will take appreciable
+            time to stop, the IPP Printer adds the 'moving-to-paused' value to
+            the Printer object's 'printer-state-reasons' attribute (see section
+            4.4.12).  When the device(s) have all stopped, the IPP Printer
+            transitions the Printer object to the 'stopped' state, removes the
+            'moving-to-paused' value, if present, and adds the 'paused' value to
+            the Printer object's 'printer-state-reasons' attribute.
+
+            When the current job(s) complete that were in the 'processing' state,
+            the IPP Printer transitions them to the 'completed' state.  When the
+            current job(s) stop in mid processing that were in the 'processing'
+            state, the IPP Printer transitions them to the 'processing-stopped'
+            state and adds the 'printer-stopped' value to the job's 'job-state-
+            reasons' attribute.
+
+            For any jobs that are 'pending' or 'pending-held', the 'printer-
+            stopped' value of the jobs' 'job-state-reasons' attribute also
+            applies.  However, the IPP Printer NEED NOT update those jobs' 'job-
+            state-reasons' attributes and only need return the 'printer-stopped'
+            value when those jobs are queried (so-called 'lazy evaluation').
+
+            Whether the Pause-Printer operation affects jobs that were submitted
+            to the device from other sources than the IPP Printer object in the
+            same way that the Pause-Printer operation affects jobs that were
+            submitted to the IPP Printer object using IPP, depends on
+            implementation, i.e., on whether the IPP protocol is being used as a
+            universal management protocol or just to manage IPP jobs,
+            respectively.
+
+            The IPP Printer MUST accept the request in any state and transition
+            the Printer to the indicated new 'printer-state' before returning as
+            follows:
+
+            Current        New      'printer   IPP Printer's response status
+            'printer-    'printer-   -state-          code and action:
+            state'       state'    reasons'
+
+            'idle'       'stopped'    'paused'  'successful-ok'
+            'processing' 'processing' 'moving-  OPTION 1: 'successful-ok';
+                                                      to-       Later, when all output has
+                                                      paused'   stopped, the 'printer-state'
+                                                                            becomes 'stopped', and the
+                                                                            'paused' value replaces the
+                                                                            'moving-to-paused' value in the
+                                                                            'printer-state-reasons'
+                                                                            attribute
+            'processing' 'stopped'    'paused'  OPTION 2: 'successful-ok';
+                                                                            all device output stopped
+                                                                            immediately
+            'stopped'    'stopped'    'paused'  'successful-ok'
+
+            Access Rights: The authenticated user (see section 8.3) performing
+            this operation must be an operator or administrator of the Printer
+            object (see Sections 1 and 8.5).   Otherwise, the IPP Printer MUST
+            reject the operation and return:  'client-error-forbidden', 'client-
+            error-not-authenticated', or 'client-error-not-authorized' as
+            appropriate.
+
+            3.2.7.1 Pause-Printer Request
+
+            The following groups of attributes are part of the Pause-Printer
+            Request:
+
+            Group 1: Operation Attributes
+
+            Natural Language and Character Set:
+            The 'attributes-charset' and 'attributes-natural-language'
+            attributes as described in section 3.1.4.1.
+
+            Target:
+            The 'printer-uri' (uri) operation attribute which is the target
+            for this operation as described in section 3.1.5.
+
+            Requesting User Name:
+            The 'requesting-user-name' (name(MAX)) attribute SHOULD be
+            supplied by the client as described in section 8.3.
+
+            3.2.7.2 Pause-Printer Response
+
+            The following groups of attributes are part of the Pause-Printer
+            Response:
+
+            Group 1: Operation Attributes
+
+            Status Message:
+            In addition to the REQUIRED status code returned in every
+            response, the response OPTIONALLY includes a 'status-message'
+            (text(255)) and/or a 'detailed-status-message' (text(MAX))
+            operation attribute as described in sections 13 and  3.1.6.
+
+            Natural Language and Character Set:
+            The 'attributes-charset' and 'attributes-natural-language'
+            attributes as described in section 3.1.4.2.
+
+            Group 2: Unsupported Attributes
+
+            See section 3.1.7 for details on returning Unsupported Attributes.
+
+   
+    """
         raise ipp.errors.ServerErrorOperationNotSupported
 
     @handler_for(ipp.OperationCodes.RESUME_PRINTER)
     def resume_printer(self, request, response):
+        """
+        3.2.8 Resume-Printer Operation
+
+        This operation allows a client to resume the Printer object
+        scheduling jobs on all its devices.  The Printer object MUST remove
+        the 'paused' and 'moving-to-paused' values from the Printer object's
+        'printer-state-reasons' attribute, if present.  If there are no other
+        reasons to keep a device paused (such as media-jam), the IPP Printer
+        is free to transition itself to the 'processing' or 'idle' states,
+        depending on whether there are jobs to be processed or not,
+        respectively, and the device(s) resume processing jobs.
+
+        If the Pause-Printer operation is supported, then the Resume-Printer
+        operation MUST be supported, and vice-versa.
+
+        The IPP Printer removes the 'printer-stopped' value from any job's
+        'job-state-reasons' attributes contained in that Printer.
+
+        The IPP Printer MUST accept the request in any state, transition the
+        Printer object to the indicated new state as follows:
+
+
+        Current    New 'printer-  IPP Printer's response status code and
+        'printer-      state'                     action:
+        state'
+
+        'idle'       'idle'         'successful-ok'
+        'processing' 'processing'   'successful-ok'
+
+        'stopped'    'processing'   'successful-ok';
+                                                   when there are jobs to be processed
+        'stopped'    'idle'         'successful-ok';
+                                                   when there are no jobs to be processed.
+
+        Access Rights: The authenticated user (see section 8.3) performing
+        this operation must be an operator or administrator of the Printer
+        object (see Sections 1 and 8.5).  Otherwise, the IPP Printer MUST
+        reject the operation and return:  'client-error-forbidden', 'client-
+        error-not-authenticated', or 'client-error-not-authorized' as
+        appropriate.
+
+        The Resume-Printer Request and Resume-Printer Response have the same
+        attribute groups and attributes as the Pause-Printer operation (see
+        sections 3.2.7.1 and 3.2.7.2).                 
+        """
         raise ipp.errors.ServerErrorOperationNotSupported
 
@@ -442,4 +639,5 @@
     @handler_for(ipp.OperationCodes.SET_PRINTER_ATTRIBUTES)
     def set_printer_attributes(self, request, response):
+
         raise ipp.errors.ServerErrorOperationNotSupported
 
@@ -699,5 +897,133 @@
     @handler_for(ipp.OperationCodes.SEND_URI)
     def send_uri(self, request, response):
-        raise ipp.errors.ServerErrorOperationNotSupported
+
+        """3.2.2 Send URI
+
+        This OPTIONAL operation is identical to the Send-Document
+        operation (see section 3.3.1) except that a client MUST supply
+        a URI reference ('document-uri' operation attribute) rather
+        than the document data itself.  If a Printer object supports
+        this operation, clients can use both Send-URI or Send-Document
+        operations to add new documents to an existing multi-document
+        Job object.  However, if a client needs to indicate that the
+        previous Send-URI or Send-Document was the last document, the
+        client MUST use the Send-Document operation with no document
+        data and the 'last-document' flag set to 'true' (rather than
+        using a Send-URI operation with no 'document-uri' operation
+        attribute).
+
+        If a Printer object supports this operation, it MUST also
+        support the Print-URI operation (see section 3.2.2).
+
+        The Printer object MUST validate the syntax and URI scheme of
+        the supplied URI before returning a response, just as in the
+        Print-URI operation.  The IPP Printer MAY validate the
+        accessibility of the document as part of the operation or
+        subsequently (see section 3.2.2).
+
+        Request
+        -------
+
+        Group 1: Operation Attributes
+            REQUIRED 'attributes-charset' 
+            REQUIRED 'attributes-natural-language' 
+            REQUIRED 'job-id' (integer(1:MAX)) and 'printer-uri' (uri)
+            REQUIRED 'document-uri' (uri)
+            OPTIONAL 'job-uri' (uri)
+            OPTIONAL 'requesting-user-name' (name(MAX))
+            OPTIONAL 'document-name' (name(MAX))
+            OPTIONAL 'compression' (type3 keyword)
+            OPTIONAL 'document-format' (mimeMediaType)
+            OPTIONAL 'document-natural-language' (naturalLanguage)
+            
+        Response
+        --------
+
+        Group 1: Operation Attributes
+            OPTIONAL 'status-message' (text(255))
+            OPTIONAL 'detailed-status-message' (text(MAX))
+            REQUIRED 'attributes-charset'
+            REQUIRED 'attributes-natural-language'
+        Group 2: Unsupported Attributes
+        Group 3: Job Object Attributes
+            REQUIRED 'job-uri' (uri)
+            REQUIRED 'job-id' (integer(1:MAX))
+            REQUIRED 'job-state' (type1 enum)
+            REQUIRED 'job-state-reasons' (1setOf type2 keyword)
+            OPTIONAL 'job-state-message' (text(MAX))
+            OPTIONAL 'number-of-intervening-jobs' (integer(0:MAX))
+
+        """
+        
+        operation = request.attribute_groups[0]
+
+        job_id = None
+        printer_uri = None
+        requesting_user_name = None
+        document_name = None
+        compression = None
+        document_format = None
+        document_natural_language = None
+        last_document = None
+
+        # required attributes
+        if 'job-id' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'job-id' attribute")
+        job_id = verify_attribute(operation['job-id'], ipp.JobId)[0]
+
+        if 'last-document' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'last-document' attribute")
+        last_document = verify_attribute(operation['last-document'], ipp.LastDocument)[0]
+
+        if 'document-uri' not in operation:
+            raise ipp.errors.ClientErrorBadRequest("Missing 'document-uri' attribute")
+        document_uri = verify_attribute(operation['document-uri'], ipp.DocumentUri)[0]
+        if not last_document:
+            raise ipp.errors.ServerErrorMultipleJobsNotSupported
+
+        # optional attributes
+        if 'printer-uri' in operation:
+            printer_uri = verify_attribute(operation['printer-uri'], ipp.PrinterUri)[0]
+            if printer_uri not in self.printer.uris:
+                raise ipp.errors.ClientErrorAttributes(
+                    str(operation['printer-uri']), operation['printer-uri'])
+
+        if 'requesting-user-name' in operation:
+            user_name = verify_attribute(
+                operation['requesting-user-name'], ipp.RequestingUserName)[0]
+
+        if 'document-name' in operation:
+            document_name = verify_attribute(
+                operation['document-name'], ipp.DocumentName)[0]
+
+        if 'compression' in operation:
+            compression = verify_attribute(
+                operation['compression'], ipp.Compression)[0]
+
+        if 'document-format' in operation:
+            document_format = verify_attribute(
+                operation['document-format'], ipp.DocumentFormat)[0]
+
+        if 'document-natural-language' in operation:
+            document_natural_language = verify_attribute(
+                operation['document_natural_language'],
+                ipp.DocumentNaturalLanguage)[0]
+
+        try:
+            self.printer.send_uri(
+                job_id,
+                document_uri,
+                document_name=document_name,
+                document_format=document_format,
+                document_natural_language=document_natural_language,
+                requesting_user_name=user_name,
+                compression=compression,
+                last_document=last_document)
+            attrs = self.printer.get_job_attributes(job_id)
+        except InvalidJobException:
+            raise ipp.errors.ClientErrorNotFound("bad job: %d" % job_id)
+
+        response.attribute_groups.append(ipp.AttributeGroup(
+            ipp.AttributeTags.JOB, attrs))
 
     @handler_for(ipp.OperationCodes.GET_JOB_ATTRIBUTES)
@@ -807,4 +1133,5 @@
     @handler_for(ipp.OperationCodes.SET_JOB_ATTRIBUTES)
     def set_job_attributes(self, request, response):
+        
         raise ipp.errors.ServerErrorOperationNotSupported
 
