Back to index

system-config-printer  1.3.9+20120706
Classes | Functions | Variables
cupshelpers.ppds Namespace Reference

Classes

class  PPDs

Functions

def ppdMakeModelSplit
def normalize
def _singleton
def _show_help
def _self_test

Variables

list __all__
list _MFR_BY_RANGE
dictionary _MFR_NAMES_BY_LOWER = {}
dictionary _HP_MODEL_BY_NAME
tuple _RE_turboprint = re.compile("turboprint")
tuple _RE_version_numbers = re.compile(" v\d(?:\d*\.\d+)?(?: |$)")
tuple _RE_ignore_suffix
tuple _RE_ignore_series = re.compile(" series| all-in-one", re.I)

Function Documentation

def cupshelpers.ppds._self_test (   argv) [private]

Definition at line 1117 of file ppds.py.

01117 
01118 def _self_test(argv):
01119     import sys, getopt
01120     try:
01121         opts, args = getopt.gnu_getopt (argv[1:], '',
01122                                         ['help',
01123                                          'deviceid',
01124                                          'list-models',
01125                                          'list-ids',
01126                                          'debug'])
01127     except getopt.GetoptError:
01128         _show_help()
01129         sys.exit (1)
01130 
01131     stdin_deviceid = False
01132     list_models = False
01133     list_ids = False
01134 
01135     for opt, optarg in opts:
01136         if opt == "--help":
01137             _show_help ()
01138             sys.exit (0)
01139         if opt == "--deviceid":
01140             stdin_deviceid = True
01141         elif opt == "--list-models":
01142             list_models = True
01143         elif opt == "--list-ids":
01144             list_ids = True
01145         elif opt == "--debug":
01146             def _dprint(x):
01147                 try:
01148                     print x
01149                 except:
01150                     pass
01151 
01152             set_debugprint_fn (_dprint)
01153 
01154     picklefile="pickled-ppds"
01155     import pickle
01156     try:
01157         f = open (picklefile, "r")
01158         cupsppds = pickle.load (f)
01159     except IOError:
01160         f = open (picklefile, "w")
01161         c = cups.Connection ()
01162         try:
01163             cupsppds = c.getPPDs2 ()
01164             print "Using getPPDs2()"
01165         except AttributeError:
01166             # Need pycups >= 1.9.52 for getPPDs2
01167             cupsppds = c.getPPDs ()
01168             print "Using getPPDs()"
01169 
01170         pickle.dump (cupsppds, f)
01171 
01172     xml_dir = os.environ.get ("top_srcdir")
01173     if xml_dir:
01174         xml_dir = os.path.join (xml_dir, "xml")
01175 
01176     ppds = PPDs (cupsppds, xml_dir=xml_dir)
01177     makes = ppds.getMakes ()
01178     models_count = 0
01179     for make in makes:
01180         models = ppds.getModels (make)
01181         models_count += len (models)
01182         if list_models:
01183             print make
01184             for model in models:
01185                 print "  " + model
01186     print "%d makes, %d models" % (len (makes), models_count)
01187     ppds.getPPDNameFromDeviceID ("HP", "PSC 2200 Series")
01188     makes = ppds.ids.keys ()
01189     models_count = 0
01190     for make in makes:
01191         models = ppds.ids[make]
01192         models_count += len (models)
01193         if list_ids:
01194             print make
01195             for model in models:
01196                 print "  %s (%d)" % (model, len (ppds.ids[make][model]))
01197                 for driver in ppds.ids[make][model]:
01198                     print "    " + driver
01199     print "%d ID makes, %d ID models" % (len (makes), models_count)
01200 
01201     print "\nID matching tests\n"
01202 
01203     MASK_STATUS = (1 << 2) - 1
01204     FLAG_INVERT = (1 << 2)
01205     FLAG_IGNORE_STATUS = (1 << 3)
01206     idlist = [
01207         # Format is:
01208         # (ID string, max status code (plus flags),
01209         #  expected ppd-make-and-model RE match)
01210 
01211         # Specific models
01212         ("MFG:EPSON;CMD:ESCPL2,BDC,D4,D4PX;MDL:Stylus D78;CLS:PRINTER;"
01213          "DES:EPSON Stylus D78;", 1, 'Epson Stylus D68'),
01214         ("MFG:Hewlett-Packard;MDL:LaserJet 1200 Series;"
01215          "CMD:MLC,PCL,POSTSCRIPT;CLS:PRINTER;", 0, 'HP LaserJet 1200'),
01216         ("MFG:Hewlett-Packard;MDL:LaserJet 3390 Series;"
01217          "CMD:MLC,PCL,POSTSCRIPT;CLS:PRINTER;", 0, 'HP LaserJet 3390'),
01218         ("MFG:Hewlett-Packard;MDL:PSC 2200 Series;CMD:MLC,PCL,PML,DW-PCL,DYN;"
01219          "CLS:PRINTER;1284.4DL:4d,4e,1;", 0, "HP PSC 22[01]0"),
01220         ("MFG:HEWLETT-PACKARD;MDL:DESKJET 990C;CMD:MLC,PCL,PML;CLS:PRINTER;"
01221          "DES:Hewlett-Packard DeskJet 990C;", 0, "HP DeskJet 990C"),
01222         ("CLASS:PRINTER;MODEL:HP LaserJet 6MP;MANUFACTURER:Hewlett-Packard;"
01223          "DESCRIPTION:Hewlett-Packard LaserJet 6MP Printer;"
01224          "COMMAND SET:PJL,MLC,PCLXL,PCL,POSTSCRIPT;", 0, "HP LaserJet 6MP"),
01225         # Canon PIXMA iP3000 (from gutenprint)
01226         ("MFG:Canon;CMD:BJL,BJRaster3,BSCCe;SOJ:TXT01;MDL:iP3000;CLS:PRINTER;"
01227          "DES:Canon iP3000;VER:1.09;STA:10;FSI:03;", 1, "Canon PIXMA iP3000"),
01228         ("MFG:HP;MDL:Deskjet 5400 series;CMD:MLC,PCL,PML,DW-PCL,DESKJET,DYN;"
01229          "1284.4DL:4d,4e,1;CLS:PRINTER;DES:5440;",
01230          1, "HP DeskJet (5440|5550)"), # foomatic-db-hpijs used to say 5440
01231         ("MFG:Hewlett-Packard;MDL:HP LaserJet 3390;"
01232          "CMD:PJL,MLC,PCL,POSTSCRIPT,PCLXL;",
01233          0, "HP LaserJet 3390"),
01234         # Ricoh printers should use PostScript versions of
01235         # manufacturer's PPDs (bug #550315 comment #8).
01236         ("MFG:RICOH;MDL:Aficio 3045;",
01237          0, "Ricoh Aficio 3045 PS"),
01238         # Don't mind which driver gets used here so long as it isn't
01239         # gutenprint (bug #645993).
01240         ("MFG:Brother;MDL:HL-2030;",
01241          0 | FLAG_INVERT | FLAG_IGNORE_STATUS, ".*Gutenprint"),
01242         # Make sure we get a colour driver for this one, see launchpad
01243         # #669152.
01244         ("MFG:Xerox;MDL:6250DP;",
01245          1, ".*(Postscript|pcl5e)"),
01246 
01247         # Generic models
01248         ("MFG:New;MDL:Unknown PS Printer;CMD:POSTSCRIPT;",
01249          2, "Generic postscript printer"),
01250         # Make sure pxlcolor is used for PCLXL.  The gutenprint driver
01251         # is black and white, and pxlcolor is the foomatic-recommended
01252         # generic driver for "Generic PCL 6/PCL XL Printer".
01253         ("MFG:New;MDL:Unknown PCL6 Printer;CMD:PCLXL;", 2,
01254          "Generic PCL 6.*pxlcolor"),
01255         ("MFG:New;MDL:Unknown PCL5e Printer;CMD:PCL5e;", 2, "Generic PCL 5e"),
01256         ("MFG:New;MDL:Unknown PCL5c Printer;CMD:PCL5c;", 2, "Generic PCL 5c"),
01257         ("MFG:New;MDL:Unknown PCL5 Printer;CMD:PCL5;", 2, "Generic PCL 5"),
01258         ("MFG:New;MDL:Unknown PCL3 Printer;CMD:PCL;", 2, "Generic PCL"),
01259         ("MFG:New;MDL:Unknown Printer;", 100, None),
01260         ]
01261 
01262     if stdin_deviceid:
01263         idlist = [(raw_input ('Device ID: '), 2, '')]
01264 
01265     all_passed = True
01266     for id, max_status_code, modelre in idlist:
01267         flags = max_status_code & ~MASK_STATUS
01268         max_status_code &= MASK_STATUS
01269         id_dict = parseDeviceID (id)
01270         (status, ppdname) = ppds.getPPDNameFromDeviceID (id_dict["MFG"],
01271                                                          id_dict["MDL"],
01272                                                          id_dict["DES"],
01273                                                          id_dict["CMD"])
01274         ppddict = ppds.getInfoFromPPDName (ppdname)
01275         if flags & FLAG_IGNORE_STATUS:
01276             status = max_status_code
01277 
01278         if status < max_status_code:
01279             success = True
01280         else:
01281             if status == max_status_code:
01282                 match = re.match (modelre,
01283                                   _singleton (ppddict['ppd-make-and-model']),
01284                                   re.I)
01285                 success = match != None
01286             else:
01287                 success = False
01288 
01289 
01290         if flags & FLAG_INVERT:
01291             success = not success
01292 
01293         if success:
01294             result = "PASS"
01295         else:
01296             result = "*** FAIL ***"
01297 
01298         print "%s: %s %s (%s)" % (result, id_dict["MFG"], id_dict["MDL"],
01299                                   _singleton (ppddict['ppd-make-and-model']))
01300         all_passed = all_passed and success
01301 
01302     if not all_passed:
01303         raise RuntimeError

Here is the call graph for this function:

def cupshelpers.ppds._show_help ( ) [private]

Definition at line 1114 of file ppds.py.

01114 
01115 def _show_help():
01116     print "usage: ppds.py [--deviceid] [--list-models] [--list-ids] [--debug]"

Here is the caller graph for this function:

def cupshelpers.ppds._singleton (   x) [private]
If we don't know whether getPPDs() or getPPDs2() was used, this
function can unwrap an item from a list in either case.

Definition at line 290 of file ppds.py.

00290 
00291 def _singleton (x):
00292     """If we don't know whether getPPDs() or getPPDs2() was used, this
00293     function can unwrap an item from a list in either case."""
00294     if isinstance (x, list):
00295         return x[0]
00296     return x

def cupshelpers.ppds.normalize (   strin)

Definition at line 244 of file ppds.py.

00244 
00245 def normalize (strin):
00246     # This function normalizes manufacturer and model names for comparing.
00247     # The string is turned to lower case and leading and trailing white
00248     # space is removed. After that each sequence of non-alphanumeric
00249     # characters (including white space) is replaced by a single space and
00250     # also at each change between letters and numbers a single space is added.
00251     # This makes the comparison only done by alphanumeric characters and the
00252     # words formed from them. So mostly two strings which sound the same when
00253     # you pronounce them are considered equal. Printer manufacturers do not
00254     # market two models whose names sound the same but differ only by
00255     # upper/lower case, spaces, dashes, ..., but in printer drivers names can
00256     # be easily supplied with these details of the name written in the wrong
00257     # way, especially if the IEEE-1284 device ID of the printer is not known.
00258     # This way we get a very reliable matching of printer model names.
00259     # Examples:
00260     # - Epson PM-A820 -> epson pm a 820
00261     # - Epson PM A820 -> epson pm a 820
00262     # - HP PhotoSmart C 8100 -> hp photosmart c 8100
00263     # - hp Photosmart C8100  -> hp photosmart c 8100
00264     lstrin = strin.strip ().lower ()
00265     normalized = ""
00266 
00267     BLANK=0
00268     ALPHA=1
00269     DIGIT=2
00270     lastchar = BLANK
00271 
00272     alnumfound = False
00273     for i in range (len (lstrin)):
00274         if lstrin[i].isalpha ():
00275             if lastchar != ALPHA and alnumfound:
00276                 normalized += " ";
00277             lastchar = ALPHA
00278         elif lstrin[i].isdigit ():
00279             if lastchar != DIGIT and alnumfound:
00280                 normalized += " ";
00281             lastchar = DIGIT
00282         else:
00283             lastchar = BLANK
00284 
00285         if lstrin[i].isalnum ():
00286             normalized += lstrin[i]
00287             alnumfound = True
00288 
00289     return normalized

Here is the caller graph for this function:

def cupshelpers.ppds.ppdMakeModelSplit (   ppd_make_and_model)
Split a ppd-make-and-model string into a canonical make and model pair.

@type ppd_make_and_model: string
@param ppd_make_and_model: IPP ppd-make-and-model attribute
@return: a string pair representing the make and the model

Definition at line 116 of file ppds.py.

00116 
00117 def ppdMakeModelSplit (ppd_make_and_model):
00118     """
00119     Split a ppd-make-and-model string into a canonical make and model pair.
00120 
00121     @type ppd_make_and_model: string
00122     @param ppd_make_and_model: IPP ppd-make-and-model attribute
00123     @return: a string pair representing the make and the model
00124     """
00125 
00126     # If the string starts with a known model name (like "LaserJet") assume
00127     # that the manufacturer name is missing and add the manufacturer name
00128     # corresponding to the model name
00129     ppd_make_and_model.strip ()
00130     make = None
00131     cleanup_make = False
00132     l = ppd_make_and_model.lower ()
00133     for mfr, regexp in _MFR_BY_RANGE:
00134         if regexp.match (l):
00135             make = mfr
00136             model = ppd_make_and_model
00137             break
00138 
00139     # Handle PPDs provided by Turboprint
00140     if make == None and _RE_turboprint.search (l):
00141         t = ppd_make_and_model.find (" TurboPrint")
00142         if t != -1:
00143             t2 = ppd_make_and_model.rfind (" TurboPrint")
00144             if t != t2:
00145                 ppd_make_and_model = ppd_make_and_model[t + 12:t2]
00146             else:
00147                 ppd_make_and_model = ppd_make_and_model[:t]
00148         try:
00149             make, model = ppd_make_and_model.split("_", 1)
00150         except:
00151             make = ppd_make_and_model
00152             model = ''
00153         make = re.sub (r"(?<=[a-z])(?=[0-9])", " ", make)
00154         make = re.sub (r"(?<=[a-z])(?=[A-Z])", " ", make)
00155         model = re.sub (r"(?<=[a-z])(?=[0-9])", " ", model)
00156         model = re.sub (r"(?<=[a-z])(?=[A-Z])", " ", model)
00157         model = re.sub (r" Jet", "Jet", model)
00158         model = re.sub (r"Photo Smart", "PhotoSmart", model)
00159         cleanup_make = True
00160 
00161     # Special handling for two-word manufacturers
00162     elif l.startswith ("konica minolta "):
00163         make = "KONICA MINOLTA"
00164         model = ppd_make_and_model[15:]
00165     elif l.startswith ("lexmark international "):
00166         make = "Lexmark"
00167         model = ppd_make_and_model[22:]
00168     elif l.startswith ("kyocera mita "):
00169         make = "Kyocera Mita"
00170         model = ppd_make_and_model[13:]
00171     elif l.startswith ("kyocera "):
00172         make = "Kyocera Mita"
00173         model = ppd_make_and_model[8:]
00174 
00175     # Finally, take the first word as the name of the manufacturer.
00176     else:
00177         cleanup_make = True
00178         try:
00179             make, model = ppd_make_and_model.split(" ", 1)
00180         except:
00181             make = ppd_make_and_model
00182             model = ''
00183 
00184     # Standardised names for manufacturers.
00185     makel = make.lower ()
00186     if cleanup_make:
00187         if (makel.startswith ("hewlett") and
00188             makel.endswith ("packard")):
00189             make = "HP"
00190             makel = "hp"
00191         elif (makel.startswith ("konica") and
00192               makel.endswith ("minolta")):
00193             make = "KONICA MINOLTA"
00194             makel = "konica minolta"
00195         else:
00196             # Fix case errors.
00197             mfr = _MFR_NAMES_BY_LOWER.get (makel)
00198             if mfr:
00199                 make = mfr
00200 
00201     # HP PostScript PPDs give NickNames like:
00202     # *NickName: "HP LaserJet 4 Plus v2013.111 Postscript (recommended)"
00203     # Find the version number and truncate at that point.  But beware,
00204     # other model names can legitimately look like version numbers,
00205     # e.g. Epson PX V500.
00206     # Truncate only if the version number has only one digit, or a dot
00207     # with digits before and after.
00208     modell = model.lower ()
00209     v = modell.find (" v")
00210     if v != -1:
00211         # Look for " v" followed by a digit, optionally followed by more
00212         # digits, a dot, and more digits; and terminated by a space of the
00213         # end of the line.
00214         vmatch = _RE_version_numbers.search (modell)
00215         if vmatch:
00216             # Found it -- truncate at that point.
00217             vstart = vmatch.start ()
00218             modell = modell[:vstart]
00219             model = model[:vstart]
00220 
00221     suffix = _RE_ignore_suffix.search (modell)
00222     if suffix:
00223         suffixstart = suffix.start ()
00224         modell = modell[:suffixstart]
00225         model = model[:suffixstart]
00226 
00227     # Remove the word "Series" if present.  Some models are referred
00228     # to as e.g. HP OfficeJet Series 300 (from hpcups, and in the
00229     # Device IDs of such models), and other groups of models are
00230     # referred to in drivers as e.g. Epson Stylus Color Series (CUPS).
00231     (model, n) = _RE_ignore_series.subn ("", model, count=1)
00232     if n:
00233         modell = model.lower ()
00234 
00235     if makel == "hp":
00236         for (name, fullname) in _HP_MODEL_BY_NAME.iteritems ():
00237             if modell.startswith (name):
00238                 model = fullname + model[len (name):]
00239                 modell = model.lower ()
00240                 break
00241 
00242     model = model.strip ()
00243     return (make, model)


Variable Documentation

Initial value:
00001 ['ppdMakeModelSplit',
00002            'PPDs']

Definition at line 34 of file ppds.py.

Initial value:
00001 {
00002     "dj": "DeskJet",
00003     "lj": "LaserJet",
00004     "oj": "OfficeJet",
00005     "color lj": "Color LaserJet",
00006     "ps ": "PhotoSmart",
00007     "hp ": ""
00008 }

Definition at line 85 of file ppds.py.

Definition at line 37 of file ppds.py.

Definition at line 81 of file ppds.py.

tuple cupshelpers.ppds._RE_ignore_series = re.compile(" series| all-in-one", re.I)

Definition at line 114 of file ppds.py.

Initial value:
00001 re.compile(","
00002                                 "| hpijs"
00003                                 "| foomatic/"
00004                                 "| - "
00005                                 "| w/"
00006                                 "| \("
00007                                 "| postscript"
00008                                 "| ps"
00009                                 "| pxl"
00010                                 "| zjs"         # hpcups
00011                                 "| zxs"         # hpcups
00012                                 "| pcl3"        # hpcups
00013                                 "| printer"     # hpcups
00014                                 "|_bt"
00015                                 "| pcl"         # Canon CQue
00016                                 "| ufr ii"      # Canon UFR II
00017                                 "| br-script"  # Brother PPDs
00018                                 )

Definition at line 96 of file ppds.py.

tuple cupshelpers.ppds._RE_turboprint = re.compile("turboprint")

Definition at line 94 of file ppds.py.

tuple cupshelpers.ppds._RE_version_numbers = re.compile(" v\d(?:\d*\.\d+)?(?: |$)")

Definition at line 95 of file ppds.py.