Get all available printers in OS X using Python

3.9k views Asked by At

Currently I am doing some tests with printers in Python, what I am trying to do is to list all the printers available.

Right now I am using PyCups library which exposes several useful APIs in the Connection class. Among these there's also getPrinters():

Here's a snippet that I use and works:

>>> import cups
>>> conn = cups.Connection ()
>>> printers = conn.getPrinters ()
>>> for printer in printers:
...     print printer, printers[printer]["device-uri"]
Brother_MFC_1910W_series
Photosmart_6520_series

I was wondering if there's any method to write the above code without using any external library. I am quite sure this can't be done without using C.

Any suggestion or reference to docs would be very appreciated. Thanks

I am using Python 3

2

There are 2 answers

5
void On BEST ANSWER

It is possible to use C libraries from Python with standard modules only. References: CUPS API, ctypes. Translating CUPS structures and calls into ctypes syntax, we get a code that works under both standard OS X Python and Python 3:

from __future__ import print_function

from ctypes import *


class cups_option_t(Structure):
    _fields_ = [
        ('name', c_char_p),
        ('value', c_char_p)
    ]


class cups_dest_t(Structure):
    _fields_ = [
        ('name', c_char_p),
        ('instance', c_char_p),
        ('is_default', c_int),
        ('num_options', c_int),
        ('cups_option_t', POINTER(cups_option_t))
    ]


cups_lib = cdll.LoadLibrary('/usr/lib/libcups.dylib')


if __name__ == '__main__':
    dests = cups_dest_t()
    dests_p = pointer(dests)    
    num_dests = cups_lib.cupsGetDests(byref(dests_p))    
    for i in range(num_dests):
        dest = dests_p[i]
        print(dest.is_default, dest.name)
        for j in range(dest.num_options):
            option = dest.cups_option_t[j]
            print('', option.name, option.value, sep='\t')    
    cups_lib.cupsFreeDests(num_dests, dests_p)

Be especially careful when using ctypes, most of errors would produce a segmentation fault.

2
Logan Byers On

You can perform a similar query using the terminal command lpstat (man for OSX). Python's builtin subprocess module would allow you to run that command and store the output. Some text parsing should provide the printer name.

from subprocess import Popen, PIPE

# "lpstat -a" prints info on printers that can accept print requests
p = Popen(['lpstat', '-a'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, errors = p.communicate()

lines = output.split('\n')
# check before you implement this parsing
printers = map(lambda x: x.split(' ')[0], lines)