- Timestamp:
- Dec 18, 2011, 11:18:16 PM (12 years ago)
- Branches:
- no-cups
- Children:
- 9eeab06
- Parents:
- d04a689
- git-author:
- Jessica B. Hamrick <jhamrick@…> (12/18/11 23:18:16)
- git-committer:
- Jessica B. Hamrick <jhamrick@…> (12/18/11 23:18:16)
- Location:
- server/lib/gutenbach
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
server/lib/gutenbach/ipp/attributegroup.py
rd04a689 rb2e077a 16 16 """ 17 17 18 def __init__(self, attribute_group_tag=None, attributes=[]):18 def __init__(self, tag=None, attributes=[]): 19 19 """Initialize an AttributeGroup. An AttributeGroup can be 20 20 initialized in three ways: 21 21 22 22 AttributeGroup() 23 AttributeGroup( attribute_group_tag)24 AttributeGroup( attribute_group_tag, attributes)23 AttributeGroup(tag) 24 AttributeGroup(tag, attributes) 25 25 26 26 Arguments: 27 27 28 attribute_group_tag -- a signed char, holds the tag of the29 28 tag -- a signed char, holds the tag of the 29 attribute group 30 30 31 31 attributes -- a list of attributes … … 33 33 """ 34 34 35 if attribute_group_tag is not None: 36 assert isinstance(attribute_group_tag, int), \ 37 "attribute_group_tag must be a character!" 38 35 if tag is not None: 36 assert isinstance(tag, int), \ 37 "tag must be a character!" 39 38 40 self. attribute_group_tag = attribute_group_tag39 self.tag = tag 41 40 self.attributes = [] 42 41 self.extend(attributes) … … 97 96 """ 98 97 99 # conver the attribute_group_tag to binary100 tag = struct.pack('>b', self. attribute_group_tag)98 # convert the tag to binary 99 tag = struct.pack('>b', self.tag) 101 100 102 101 # convert each of the attributes to binary … … 107 106 108 107 def __repr__(self): 109 return '<IPPAttributeGroup (%r, %r)>' % (self. attribute_group_tag, self.attributes)108 return '<IPPAttributeGroup (%r, %r)>' % (self.tag, self.attributes) -
server/lib/gutenbach/server/__init__.py
rd04a689 rb2e077a 1 from requests import GutenbachIPP Handler1 from requests import GutenbachIPPServer 2 2 import BaseHTTPServer 3 3 import logging … … 8 8 def start(): 9 9 server_address = ('', 8000) 10 httpd = BaseHTTPServer.HTTPServer(server_address, GutenbachIPP Handler)10 httpd = BaseHTTPServer.HTTPServer(server_address, GutenbachIPPServer) 11 11 httpd.serve_forever() 12 12 -
server/lib/gutenbach/server/exceptions.py
rdf51061 rb2e077a 12 12 def __str__(self): 13 13 return self.message 14 15 class MalformedIPPRequestException(Exception): 16 def __init__(self, message): 17 self.message = message 18 19 def __str__(self): 20 return self.message -
server/lib/gutenbach/server/job.py
rd04a689 rb2e077a 7 7 class Job(object): 8 8 9 attributes = [ 10 "job-id", 11 "job-name", 12 "job-originating-user-name", 13 "job-k-octets", 14 "job-state", 15 "job-printer-uri" 16 ] 17 9 18 def __init__(self, document=None): 10 19 """Initialize a Gutenbach job. … … 14 23 """ 15 24 16 self._jobid = None 17 self._status = 'initializing' 25 self._id = None 26 self._name = document 27 self._status = None 18 28 self._document = document 19 29 self._printer = None 20 30 21 31 @property 22 def jobid(self): 23 return self._jobid 32 def job_id(self): 33 return ipp.Attribute( 34 'job-id', 35 [ipp.Value(ipp.Tags.INTEGER, self._id)]) 24 36 25 @jobid.setter 26 def jobid(self, val): 27 raise AttributeError("Setting jobid is illegal!") 37 @property 38 def job_name(self): 39 return ipp.Attribute( 40 'job-name', 41 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, self._name)]) 28 42 43 # XXX: we need to actually calculate this! 44 @property 45 def job_originating_user_name(self): 46 return ipp.Attribute( 47 'job-originating-user-name', 48 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, "jhamrick")]) 49 50 # XXX: we need to actually calculate this! 51 @property 52 def job_k_octets(self): 53 return ipp.Attribute( 54 'job-k-octets', 55 [ipp.Value(ipp.Tags.INTEGER, 1)]) 56 57 @property 58 def job_state(self): 59 return ipp.Attribute( 60 'job-state', 61 [ipp.Value(ipp.Tags.ENUM, self._status)]) 62 63 @property 64 def job_printer_uri(self): 65 return ipp.Attribute( 66 'job-printer-uri', 67 [ipp.Value(ipp.Tags.URI, self._printer._uri)]) 68 69 def get_job_attributes(self, request): 70 attributes = [getattr(self, attr.replace("-", "_")) for attr in self.attributes] 71 return attributes 72 73 74 ####### 29 75 @property 30 76 def document(self): … … 41 87 return self._status 42 88 43 @status.setter44 def status(self, val):45 raise AttributeError(46 "Setting status directly is illegal! " + \47 "Please use enqueue(), play(), or finish().")48 49 89 @property 50 90 def printer(self): 51 91 return self._printer 52 92 53 @printer.setter 54 def printer(self, val): 55 raise AttributeError( 56 "Setting printer directly is illegal! " + \ 57 "Please use enqueue().") 58 59 def enqueue(self, printer, jobid): 60 if self.status != 'initializing': 93 def enqueue(self, printer, job_id): 94 if self._status != None: 61 95 raise InvalidJobException( 62 96 "Cannot enqueue a job that has " + \ 63 97 "already been initialized!") 64 98 self._printer = printer 65 self._job id = jobid66 self._status = 'active'99 self._job_id = job_id 100 self._status = const.JobStates.PENDING 67 101 68 102 def play(self): … … 71 105 "Cannot play an inactive job!") 72 106 73 self._status = 'playing'107 self._status = const.JobStates.PROCESSING 74 108 # TODO: add external call to music player 75 109 print "Playing job %s" % str(self) 76 self. printer.complete_job(self.jobid)110 self._printer.complete_job(self._id) 77 111 78 112 def finish(self): 79 self._status = 'finished'113 self._status = const.JobStates.COMPLETE 80 114 81 115 def __repr__(self): … … 84 118 def __str__(self): 85 119 return "<Job %d '%s'>" % \ 86 (self. jobid if self.jobid is not None else -1, \87 self.document)120 (self._id if self._id is not None else -1, \ 121 self._document) -
server/lib/gutenbach/server/printer.py
rd04a689 rb2e077a 1 #import alsaaudio as aa 1 2 from .exceptions import InvalidJobException, InvalidPrinterStateException 2 3 from gutenbach.ipp.attribute import Attribute 3 import alsaaudio as aa 4 import gutenbach.ipp 4 import gutenbach.ipp as ipp 5 import gutenbach.ipp.constants as const 6 import logging 7 import time 5 8 6 9 # initialize logger 7 10 logger = logging.getLogger(__name__) 8 11 9 class Printer(object): 10 11 def __init__(self, name, card, mixer): 12 13 self.name = name 14 15 if card >= len(aa.cards()): 16 raise aa.ALSAAudioError( 17 "Audio card at index %d does not exist!" % card) 18 elif mixer not in aa.mixers(card): 19 raise aa.ALSAAudioError( 20 "Audio mixer '%s' does not exist!" % mixer) 12 class GutenbachPrinter(object): 13 14 attributes = [ 15 "printer-uri-supported", 16 "uri-authentication-supported", 17 "uri-security-supported", 18 "printer-name", 19 "printer-state", 20 "printer-state-reasons", 21 "ipp-versions-supported", 22 "operations-supported", 23 "charset-configured", 24 "charset-supported", 25 "natural-language-configured", 26 "generated-natural-language-supported", 27 "document-format-default", 28 "document-format-supported", 29 "printer-is-accepting-jobs", 30 "queued-job-count", 31 "pdl-override-supported", 32 "printer-up-time", 33 "compression-supported"] 34 35 #def __init__(self, name, card, mixer): 36 def __init__(self, name): 37 38 self._name = name 39 self._uri = "ipp://localhost:8000/printers/" + self._name 40 self._time_created = int(time.time()) 41 42 # if card >= len(aa.cards()): 43 # raise aa.ALSAAudioError( 44 # "Audio card at index %d does not exist!" % card) 45 # elif mixer not in aa.mixers(card): 46 # raise aa.ALSAAudioError( 47 # "Audio mixer '%s' does not exist!" % mixer) 21 48 22 self.card = card23 self.mixer = mixer49 # self.card = card 50 # self.mixer = mixer 24 51 25 52 self.finished_jobs = [] … … 29 56 self._next_jobid = 0 30 57 58 ## Printer attributes 59 @property 60 def printer_uri_supported(self): 61 return ipp.Attribute( 62 "printer-uri-supported", 63 [ipp.Value(ipp.Tags.URI, self._uri)]) 64 65 @property 66 def uri_authentication_supported(self): 67 return ipp.Attribute( 68 "uri-authentication-supported", 69 [ipp.Value(ipp.Tags.KEYWORD, "none")]) 70 71 @property 72 def uri_security_supported(self): 73 return ipp.Attribute( 74 "uri-security-supported", 75 [ipp.Value(ipp.Tags.KEYWORD, "none")]) 76 77 @property 78 def printer_name(self): 79 return ipp.Attribute( 80 "printer-name", 81 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, self._name)]) 82 83 @property 84 def printer_state(self): 85 return ipp.Attribute( 86 "printer-state", 87 [ipp.Value(ipp.Tags.ENUM, const.PrinterStates.IDLE)]) 88 89 @property 90 def printer_state_reasons(self): 91 return ipp.Attribute( 92 "printer-state-reasons", 93 [ipp.Value(ipp.Tags.KEYWORD, "none")]) 94 95 @property 96 def ipp_versions_supported(self): 97 return ipp.Attribute( 98 "ipp-versions-supported", 99 [ipp.Value(ipp.Tags.KEYWORD, "1.0"), 100 ipp.Value(ipp.Tags.KEYWORD, "1.1")]) 101 102 # XXX: We should query ourself for the supported operations 103 @property 104 def operations_supported(self): 105 return ipp.Attribute( 106 "operations-supported", 107 [ipp.Value(ipp.Tags.ENUM, const.Operations.GET_JOBS)]) 108 109 @property 110 def charset_configured(self): 111 return ipp.Attribute( 112 "charset-configured", 113 [ipp.Value(ipp.Tags.CHARSET, "utf-8")]) 114 115 @property 116 def charset_supported(self): 117 return ipp.Attribute( 118 "charset-supported", 119 [ipp.Value(ipp.Tags.CHARSET, "utf-8")]) 120 121 @property 122 def natural_language_configured(self): 123 return ipp.Attribute( 124 "natural-language-configured", 125 [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")]) 126 127 @property 128 def generated_natural_language_supported(self): 129 return ipp.Attribute( 130 "generated-natural-language-supported", 131 [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")]) 132 133 @property 134 def document_format_default(self): 135 return ipp.Attribute( 136 "document-format-default", 137 [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream")]) 138 139 @property 140 def document_format_supported(self): 141 return ipp.Attribute( 142 "document-format-supported", 143 [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream"), 144 ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "audio/mp3")]) 145 146 @property 147 def printer_is_accepting_jobs(self): 148 return ipp.Attribute( 149 "printer-is-accepting-jobs", 150 [ipp.Value(ipp.Tags.BOOLEAN, True)]) 151 152 @property 153 def queued_job_count(self): 154 return ipp.Attribute( 155 "queued-job-count", 156 [ipp.Value(ipp.Tags.INTEGER, len(self.active_jobs))]) 157 158 @property 159 def pdl_override_supported(self): 160 return ipp.Attribute( 161 "pdl-override-supported", 162 [ipp.Value(ipp.Tags.KEYWORD, "not-attempted")]) 163 164 @property 165 def printer_up_time(self): 166 return ipp.Attribute( 167 "printer-up-time", 168 [ipp.Value(ipp.Tags.INTEGER, int(time.time()) - self._time_created)]) 169 170 @property 171 def compression_supported(self): 172 return ipp.Attribute( 173 "compression-supported", 174 [ipp.Value(ipp.Tags.KEYWORD, "none")]) 175 176 def get_printer_attributes(self, request): 177 attributes = [getattr(self, attr.replace("-", "_")) for attr in self.attributes] 178 return attributes 179 180 ## Printer operations 31 181 @property 32 182 def next_jobid(self): 33 183 self._next_jobid += 1 34 184 return self._next_jobid 35 36 @next_jobid.setter37 def next_jobid(self, val):38 raise AttributeError("Setting next_jobid is illegal!")39 185 40 186 def print_job(self, job): … … 75 221 return self.jobs[jobid] 76 222 223 def get_jobs(self): 224 jobs = [self.jobs[job_id] for job_id in self.active_jobs] 225 return jobs 226 77 227 def __repr__(self): 78 228 return str(self) 79 229 80 230 def __str__(self): 81 return "<Printer '%s'>" % self. name231 return "<Printer '%s'>" % self._name -
server/lib/gutenbach/server/requests.py
rd04a689 rb2e077a 1 1 import BaseHTTPServer 2 import gutenbach.ipp 2 import gutenbach.ipp as ipp 3 3 import gutenbach.ipp.constants as const 4 from gutenbach.server.printer import GutenbachPrinter 5 from gutenbach.server.exceptions import MalformedIPPRequestException 4 6 import logging 5 import time6 7 7 8 # initialize logger … … 20 21 return f 21 22 22 class IPPRequestHandler(object): 23 """A generic base class for IPP requests. Provides a dispatch 24 function to conver request operation ids to handler functions. 25 26 """ 23 class GutenbachRequestHandler(object): 24 25 def __init__(self): 26 self.printers = { 27 "test": GutenbachPrinter(name="test") 28 } 29 self.default = "test" 27 30 28 def _ipp_dispatch(self, request): 31 def handle(self, request, response): 32 # look up the handler 33 handler = None 29 34 for d in dir(self): 30 35 if getattr(getattr(self, d), "ipp_operation", None) == request.operation_id: 31 return getattr(self, d) 32 return self.unknown_operation 36 handler = getattr(self, d) 37 break 38 # we couldn't find a handler, so default to unknown operation 39 if handler is None: 40 handler = self.unknown_operation 41 # call the handler 42 handler(request, response) 33 43 34 44 def unknown_operation(self, request, response): 35 print "Received UNKNOWN OPERATION%x" % request.operation_id45 print "Received unknown operation %x" % request.operation_id 36 46 response.operation_id = const.StatusCodes.OPERATION_NOT_SUPPORTED 37 47 38 class PrinterRequestHandler(IPPRequestHandler): 39 """This handles requests that are printer-specific: for example, 40 the printer's name or state. 41 42 """ 43 44 def __init__(self, name): 45 self.name = name 46 47 @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES) 48 def get_printer_attributes(self, request, response): 49 printer_attributes = ipp.AttributeGroup(const.AttributeTags.PRINTER) 50 printer_attributes.append(ipp.Attribute( 51 "printer-uri-supported", 52 [ipp.Value(ipp.Tags.URI, "ipp://localhost:8000/printers/" + self.name)])) 53 54 printer_attributes.append(ipp.Attribute( 55 "uri-authentication-supported", 56 [ipp.Value(ipp.Tags.KEYWORD, "none")])) 57 58 printer_attributes.append(ipp.Attribute( 59 "uri-security-supported", 60 [ipp.Value(ipp.Tags.KEYWORD, "none")])) 61 62 printer_attributes.append(ipp.Attribute( 63 "printer-name", 64 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, self.name)])) 65 66 printer_attributes.append(ipp.Attribute( 67 "printer-state", 68 [ipp.Value(ipp.Tags.ENUM, const.PrinterStates.IDLE)])) 69 70 printer_attributes.append(ipp.Attribute( 71 "printer-state-reasons", 72 [ipp.Value(ipp.Tags.KEYWORD, "none")])) 73 74 printer_attributes.append(ipp.Attribute( 75 "ipp-versions-supported", 76 [ipp.Value(ipp.Tags.KEYWORD, "1.0"), 77 ipp.Value(ipp.Tags.KEYWORD, "1.1")])) 78 79 # XXX: We should query ourself for the supported operations 80 printer_attributes.append(ipp.Attribute( 81 "operations-supported", 82 [ipp.Value(ipp.Tags.ENUM, const.Operations.GET_JOBS)])) 83 84 printer_attributes.append(ipp.Attribute( 85 "charset-configured", 86 [ipp.Value(ipp.Tags.CHARSET, "utf-8")])) 87 88 printer_attributes.append(ipp.Attribute( 89 "charset-supported", 90 [ipp.Value(ipp.Tags.CHARSET, "utf-8")])) 91 92 printer_attributes.append(ipp.Attribute( 93 "natural-language-configured", 94 [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")])) 95 96 printer_attributes.append(ipp.Attribute( 97 "generated-natural-language-supported", 98 [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, "en-us")])) 99 100 printer_attributes.append(ipp.Attribute( 101 "document-format-default", 102 [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream")])) 103 104 printer_attributes.append(ipp.Attribute( 105 "document-format-supported", 106 [ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "application/octet-stream"), 107 ipp.Value(ipp.Tags.MIME_MEDIA_TYPE, "audio/mp3")])) 108 109 printer_attributes.append(ipp.Attribute( 110 "printer-is-accepting-jobs", 111 [ipp.Value(ipp.Tags.BOOLEAN, True)])) 112 113 printer_attributes.append(ipp.Attribute( 114 "queued-job-count", 115 [ipp.Value(ipp.Tags.INTEGER, 1)])) 116 117 printer_attributes.append(ipp.Attribute( 118 "pdl-override-supported", 119 [ipp.Value(ipp.Tags.KEYWORD, "not-attempted")])) 120 121 printer_attributes.append(ipp.Attribute( 122 "printer-up-time", 123 [ipp.Value(ipp.Tags.INTEGER, int(time.time()))])) 124 125 printer_attributes.append(ipp.Attribute( 126 "compression-supported", 127 [ipp.Value(ipp.Tags.KEYWORD, "none")])) 128 129 response.attribute_groups.append(printer_attributes) 130 response.operation_id = const.StatusCodes.OK 131 print "get_printer_attributes called" 132 133 class RootRequestHandler(IPPRequestHandler): 134 printers = [PrinterRequestHandler(name="sipbmp3")] 48 def _get_printer_attributes(self, printer, request, response): 49 response.attribute_groups.append(ipp.AttributeGroup( 50 const.AttributeTags.PRINTER, 51 printer.get_printer_attributes(request))) 52 53 def _get_job_attributes(self, job_id, printer, request, response): 54 response.attribute_groups.append(ipp.AttributeGroup( 55 const.AttributeTags.JOB, 56 job.get_job_attributes(request))) 57 58 def _get_printer_name(self, request): 59 # make sure the first group is an OPERATION group 60 group_tag = request.attribute_groups[0].tag 61 if group_tag != const.AttributeTags.OPERATION: 62 raise MalformedIPPRequestException, \ 63 "Expected OPERATION group tag, got %d\n", group_tag 64 65 # make sure the printer-uri value is appropriate 66 printername_attr = request.attribute_groups[0]['printer-uri'] 67 printername_value_tag = printername_attr.values[0].value_tag 68 if printername_value_tag != const.CharacterStringTags.URI: 69 raise MalformedIPPRequestException, \ 70 "Expected URI value tag, got %s" % printername_value_tag 71 72 # actually get the printer name 73 printername_value = printername_attr.values[0].value 74 # XXX: hack -- CUPS will strip the port from the request, so 75 # we can't do an exact comparison (also the hostname might be 76 # different, depending on the CNAME or whether it's localhost) 77 printername = printername_value.split("/")[-1] 78 79 # make sure the printername is valid 80 if printername not in self.printers: 81 raise ValueError, "Invalid printer uri: %s" % printername_value 82 83 return printername 135 84 136 85 @handler_for(const.Operations.CUPS_GET_DEFAULT) 137 86 def cups_get_default(self, request, response): 138 87 print "get_default called" 139 return self.printers[0].get_printer_attributes(request, response) 88 self._get_printer_attributes(self.printers[self.default], request, response) 89 response.operation_id = const.StatusCodes.OK 90 91 @handler_for(const.Operations.GET_PRINTER_ATTRIBUTES) 92 def get_printer_attributes(self, request, response): 93 print "get_printer_attributes called" 94 95 # this is just like cups_get_default, except the printer name 96 # is given 97 printername = self._get_printer_name(request) 98 self._get_printer_attributes(self.printers[printername], request, response) 99 response.operation_id = const.StatusCodes.OK 140 100 141 101 @handler_for(const.Operations.CUPS_GET_PRINTERS) 142 102 def cups_get_printers(self, request, response): 143 103 print "get_printers called" 144 response.operation_id = const.StatusCodes.OK104 145 105 # Each printer will append a new printer attribute group. 146 for p in self.printers: 147 p.get_printer_attributes(request, response) 106 for printer in self.printers: 107 self._get_printer_attributes(self.printers[printer], request, response) 108 response.operation_id = const.StatusCodes.OK 148 109 149 110 @handler_for(const.Operations.CUPS_GET_CLASSES) … … 153 114 # We have no printer classes, so nothing to return. 154 115 155 class GutenbachIPPHandler(BaseHTTPServer.BaseHTTPRequestHandler): 116 @handler_for(const.Operations.GET_JOBS) 117 def get_jobs(self, request, response): 118 print "get_jobs called" 119 120 printername = self._get_printer_name(request) 121 # Each job will append a new job attribute group. 122 for job in self.printers[printername].get_jobs(): 123 self._get_job_attributes(job, request, response) 124 response.operation_id = const.StatusCodes.OK 125 126 class GutenbachIPPServer(BaseHTTPServer.BaseHTTPRequestHandler): 156 127 def setup(self): 157 self.root = RootRequestHandler()128 self.root = GutenbachRequestHandler() 158 129 BaseHTTPServer.BaseHTTPRequestHandler.setup(self) 159 130 … … 196 167 197 168 # Get the handler and pass it the request and response objects 198 handler = self.root._ipp_dispatch(request) 199 handler(request, response) 169 self.root.handle(request, response) 200 170 print "Sending response:", repr(response) 201 171 … … 207 177 self.wfile.write(response.packed_value) 208 178 209 def get_jobs(self, request, response_kwargs):210 """get-jobs response"""211 212 # Job attributes213 job_attributes = [214 ipp.Attribute(215 'job-id',216 [ipp.Value(ipp.Tags.INTEGER, 12345)]),217 ipp.Attribute(218 'job-name',219 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, 'foo')]),220 ipp.Attribute(221 'job-originating-user-name',222 [ipp.Value(ipp.Tags.NAME_WITHOUT_LANGUAGE, 'jhamrick')]),223 ipp.Attribute(224 'job-k-octets',225 [ipp.Value(ipp.Tags.INTEGER, 1)]),226 ipp.Attribute(227 'job-state',228 [ipp.Value(ipp.Tags.ENUM, const.JobStates.HELD)]),229 ipp.Attribute(230 'job-printer-uri',231 [ipp.Value(ipp.Tags.URI, 'ipp://localhost:8000/printers/foo')])232 ]233 # Job attribute group234 job_attribute_group = ipp.AttributeGroup(235 const.AttributeTags.JOB,236 job_attributes)237 238 # Operation attributions239 op_attributes = [240 ipp.Attribute(241 'attributes-charset',242 [ipp.Value(ipp.Tags.CHARSET, 'utf-8')]),243 ipp.Attribute(244 'attributes-natural-language',245 [ipp.Value(ipp.Tags.NATURAL_LANGUAGE, 'en-us')])246 ]247 # Operation attribution group248 op_attributes_group = ipp.AttributeGroup(249 const.AttributeTags.OPERATION,250 op_attributes)251 252 # Setup the actual response dictionary253 response_kwargs['attribute_groups'] = [op_attributes_group,job_attribute_group]254 response_kwargs['operation_id'] = const.StatusCodes.OK255 256 return response_kwargs257 258 179 ##### Printer Commands 259 180
Note: See TracChangeset
for help on using the changeset viewer.