1 diff -Naur client175_0.7-original/BeautifulSoup.py client175_0.7/BeautifulSoup.py
2 --- client175_0.7-original/BeautifulSoup.py 2010-05-14 12:57:39.000000000 +0200
3 +++ client175_0.7/BeautifulSoup.py 2021-08-03 14:39:30.213509172 +0200
5 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT.
8 -from __future__ import generators
11 __author__ = "Leonard Richardson (leonardr@segfault.org)"
12 __version__ = "3.0.8.1"
15 from sgmllib import SGMLParser, SGMLParseError
23 - from htmlentitydefs import name2codepoint
24 + from html.entities import name2codepoint
30 #These hacks make Beautiful Soup able to parse XML with namespaces
31 sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
32 -markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
33 +_markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
35 DEFAULT_OUTPUT_ENCODING = "utf-8"
38 #this element (and any children) hadn't been parsed. Connect
40 lastChild = self._lastRecursiveChild()
41 - nextElement = lastChild.next
42 + nextElement = lastChild.__next__
45 self.previous.next = nextElement
49 def insert(self, position, newChild):
50 - if isinstance(newChild, basestring) \
51 + if isinstance(newChild, str) \
52 and not isinstance(newChild, NavigableString):
53 newChild = NavigableString(newChild)
56 newChild.nextSibling.previousSibling = newChild
57 newChildsLastElement.next = nextChild
59 - if newChildsLastElement.next:
60 + if newChildsLastElement.__next__:
61 newChildsLastElement.next.previous = newChildsLastElement
62 self.contents.insert(position, newChild)
65 return [element for element in generator()
66 if isinstance(element, Tag)]
67 # findAll*('tag-name')
68 - elif isinstance(name, basestring):
69 + elif isinstance(name, str):
70 return [element for element in generator()
71 if isinstance(element, Tag) and
83 def nextGenerator(self):
90 def nextSiblingGenerator(self):
92 def toEncoding(self, s, encoding=None):
93 """Encodes an object to a string in some encoding, or to Unicode.
95 - if isinstance(s, unicode):
96 + if isinstance(s, str):
98 s = s.encode(encoding)
99 elif isinstance(s, str):
101 s = s.encode(encoding)
107 s = self.toEncoding(str(s), encoding)
113 -class NavigableString(unicode, PageElement):
114 +class NavigableString(str, PageElement):
116 def __new__(cls, value):
117 """Create a new NavigableString.
119 passed in to the superclass's __new__ or the superclass won't know
120 how to handle non-ASCII characters.
122 - if isinstance(value, unicode):
123 - return unicode.__new__(cls, value)
124 - return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
125 + if isinstance(value, str):
126 + return str.__new__(cls, value)
127 + return str.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
129 def __getnewargs__(self):
130 return (NavigableString.__str__(self),)
135 - raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
136 + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, attr))
138 def __unicode__(self):
139 return str(self).decode(DEFAULT_OUTPUT_ENCODING)
142 "Cheap function to invert a hash."
144 - for k,v in h.items():
145 + for k,v in list(h.items()):
149 @@ -502,23 +502,23 @@
152 if self.convertHTMLEntities and x in name2codepoint:
153 - return unichr(name2codepoint[x])
154 + return chr(name2codepoint[x])
155 elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
156 if self.convertXMLEntities:
157 return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
161 elif len(x) > 0 and x[0] == '#':
162 # Handle numeric entities
163 if len(x) > 1 and x[1] == 'x':
164 - return unichr(int(x[2:], 16))
165 + return chr(int(x[2:], 16))
167 - return unichr(int(x[1:]))
168 + return chr(int(x[1:]))
170 elif self.escapeUnrecognizedEntities:
171 - return u'&%s;' % x
172 + return '&%s;' % x
177 def __init__(self, parser, name, attrs=None, parent=None,
179 @@ -541,11 +541,11 @@
180 self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
182 # Convert any HTML, XML, or numeric entities in the attribute values.
183 - convert = lambda(k, val): (k,
184 + convert = lambda k_val: (k_val[0],
185 re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
186 self._convertEntities,
188 - self.attrs = map(convert, self.attrs)
190 + self.attrs = list(map(convert, self.attrs))
193 if (len(self.contents) == 1
194 @@ -559,16 +559,16 @@
196 string = property(getString, setString)
198 - def getText(self, separator=u""):
199 + def getText(self, separator=""):
200 if not len(self.contents):
202 - stopNode = self._lastRecursiveChild().next
204 + stopNode = self._lastRecursiveChild().__next__
206 current = self.contents[0]
207 while current is not stopNode:
208 if isinstance(current, NavigableString):
209 strings.append(current.strip())
210 - current = current.next
211 + current = current.__next__
212 return separator.join(strings)
214 text = property(getText)
216 raise ValueError("Tag.index: element not in tag")
218 def has_key(self, key):
219 - return self._getAttrMap().has_key(key)
220 + return key in self._getAttrMap()
222 def __getitem__(self, key):
223 """tag[key] returns the value of the 'key' attribute for the tag,
225 def __contains__(self, x):
226 return x in self.contents
228 - def __nonzero__(self):
229 + def __bool__(self):
230 "A tag is non-None even if it has no contents."
233 @@ -635,14 +635,14 @@
234 #We don't break because bad HTML can define the same
235 #attribute multiple times.
237 - if self.attrMap.has_key(key):
238 + if key in self.attrMap:
239 del self.attrMap[key]
241 def __call__(self, *args, **kwargs):
242 """Calling a tag like a function is the same as calling its
243 findAll() method. Eg. tag('a') returns a list of all the A tags
244 found within this tag."""
245 - return apply(self.findAll, args, kwargs)
246 + return self.findAll(*args, **kwargs)
248 def __getattr__(self, tag):
249 #print "Getattr %s.%s" % (self.__class__, tag)
251 return self.find(tag[:-3])
252 elif tag.find('__') != 0:
253 return self.find(tag)
254 - raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
255 + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__, tag))
257 def __eq__(self, other):
258 """Returns true iff this tag has the same name, the same attributes,
261 for key, val in self.attrs:
263 - if isinstance(val, basestring):
264 + if isinstance(val, str):
265 if self.containsSubstitutions and '%SOUP-ENCODING%' in val:
266 val = self.substituteEncoding(val, encoding)
270 current = self.contents[0]
271 while current is not None:
272 - next = current.next
273 + next = current.__next__
274 if isinstance(current, Tag):
275 del current.contents[:]
276 current.parent = None
277 @@ -873,11 +873,11 @@
278 def recursiveChildGenerator(self):
279 if not len(self.contents):
281 - stopNode = self._lastRecursiveChild().next
282 + stopNode = self._lastRecursiveChild().__next__
283 current = self.contents[0]
284 while current is not stopNode:
286 - current = current.next
287 + current = current.__next__
290 # Next, a couple classes to represent queries and their results.
293 def __init__(self, name=None, attrs={}, text=None, **kwargs):
295 - if isinstance(attrs, basestring):
296 + if isinstance(attrs, str):
297 kwargs['class'] = _match_css_class(attrs)
304 - for attr, matchAgainst in self.attrs.items():
305 + for attr, matchAgainst in list(self.attrs.items()):
306 if not markupAttrMap:
307 if hasattr(markupAttrs, 'get'):
308 markupAttrMap = markupAttrs
309 @@ -961,12 +961,12 @@
310 found = self.searchTag(markup)
311 # If it's text, make sure the text matches.
312 elif isinstance(markup, NavigableString) or \
313 - isinstance(markup, basestring):
314 + isinstance(markup, str):
315 if self._matches(markup, self.text):
318 - raise Exception, "I don't know how to match against a %s" \
320 + raise Exception("I don't know how to match against a %s" \
321 + % markup.__class__)
324 def _matches(self, markup, matchAgainst):
326 #other ways of matching match the tag name as a string.
327 if isinstance(markup, Tag):
329 - if markup and not isinstance(markup, basestring):
330 - markup = unicode(markup)
331 + if markup and not isinstance(markup, str):
332 + markup = str(markup)
333 #Now we know that chunk is either a string, or None.
334 if hasattr(matchAgainst, 'match'):
335 # It's a regexp object.
336 @@ -990,10 +990,10 @@
337 elif hasattr(matchAgainst, '__iter__'): # list-like
338 result = markup in matchAgainst
339 elif hasattr(matchAgainst, 'items'):
340 - result = markup.has_key(matchAgainst)
341 - elif matchAgainst and isinstance(markup, basestring):
342 - if isinstance(markup, unicode):
343 - matchAgainst = unicode(matchAgainst)
344 + result = matchAgainst in markup
345 + elif matchAgainst and isinstance(markup, str):
346 + if isinstance(markup, str):
347 + matchAgainst = str(matchAgainst)
349 matchAgainst = str(matchAgainst)
351 @@ -1018,7 +1018,7 @@
353 if hasattr(portion, 'items'):
354 #It's a map. Merge it.
355 - for k,v in portion.items():
356 + for k,v in list(portion.items()):
358 elif hasattr(portion, '__iter__'): # is a list
359 #It's a list. Map each item to the default.
360 @@ -1061,7 +1061,7 @@
361 lambda x: '<!' + x.group(1) + '>')
364 - ROOT_TAG_NAME = u'[document]'
365 + ROOT_TAG_NAME = '[document]'
367 HTML_ENTITIES = "html"
369 @@ -1157,14 +1157,14 @@
370 def _feed(self, inDocumentEncoding=None, isHTML=False):
371 # Convert the document to Unicode.
373 - if isinstance(markup, unicode):
374 + if isinstance(markup, str):
375 if not hasattr(self, 'originalEncoding'):
376 self.originalEncoding = None
378 dammit = UnicodeDammit\
379 (markup, [self.fromEncoding, inDocumentEncoding],
380 smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
381 - markup = dammit.unicode
382 + markup = dammit.str
383 self.originalEncoding = dammit.originalEncoding
384 self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
386 @@ -1203,8 +1203,8 @@
387 def isSelfClosingTag(self, name):
388 """Returns true iff the given string is the name of a
389 self-closing tag according to this parser."""
390 - return self.SELF_CLOSING_TAGS.has_key(name) \
391 - or self.instanceSelfClosingTags.has_key(name)
392 + return name in self.SELF_CLOSING_TAGS \
393 + or name in self.instanceSelfClosingTags
396 Tag.__init__(self, self, self.ROOT_TAG_NAME)
397 @@ -1233,7 +1233,7 @@
399 def endData(self, containerClass=NavigableString):
401 - currentData = u''.join(self.currentData)
402 + currentData = ''.join(self.currentData)
403 if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
404 not set([tag.name for tag in self.tagStack]).intersection(
405 self.PRESERVE_WHITESPACE_TAGS)):
406 @@ -1296,7 +1296,7 @@
408 nestingResetTriggers = self.NESTABLE_TAGS.get(name)
409 isNestable = nestingResetTriggers != None
410 - isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
411 + isResetNesting = name in self.RESET_NESTING_TAGS
414 for i in range(len(self.tagStack)-1, 0, -1):
415 @@ -1309,7 +1309,7 @@
416 if (nestingResetTriggers is not None
417 and p.name in nestingResetTriggers) \
418 or (nestingResetTriggers is None and isResetNesting
419 - and self.RESET_NESTING_TAGS.has_key(p.name)):
420 + and p.name in self.RESET_NESTING_TAGS):
422 #If we encounter one of the nesting reset triggers
423 #peculiar to this tag, or we encounter another tag
424 @@ -1380,7 +1380,7 @@
425 object, possibly one with a %SOUP-ENCODING% slot into which an
426 encoding will be plugged later."""
427 if text[:3] == "xml":
428 - text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
429 + text = "xml version='1.0' encoding='%SOUP-ENCODING%'"
430 self._toStringSubclass(text, ProcessingInstruction)
432 def handle_comment(self, text):
433 @@ -1390,7 +1390,7 @@
434 def handle_charref(self, ref):
435 "Handle character references as data."
436 if self.convertEntities:
437 - data = unichr(int(ref))
438 + data = chr(int(ref))
441 self.handle_data(data)
442 @@ -1402,7 +1402,7 @@
444 if self.convertHTMLEntities:
446 - data = unichr(name2codepoint[ref])
447 + data = chr(name2codepoint[ref])
451 @@ -1511,7 +1511,7 @@
452 BeautifulStoneSoup before writing your own subclass."""
454 def __init__(self, *args, **kwargs):
455 - if not kwargs.has_key('smartQuotesTo'):
456 + if 'smartQuotesTo' not in kwargs:
457 kwargs['smartQuotesTo'] = self.HTML_ENTITIES
458 kwargs['isHTML'] = True
459 BeautifulStoneSoup.__init__(self, *args, **kwargs)
460 @@ -1694,7 +1694,7 @@
462 if (isinstance(tag, Tag) and len(tag.contents) == 1 and
463 isinstance(tag.contents[0], NavigableString) and
464 - not parent.attrMap.has_key(tag.name)):
465 + tag.name not in parent.attrMap):
466 parent[tag.name] = tag.contents[0]
467 BeautifulStoneSoup.popTag(self)
469 @@ -1768,9 +1768,9 @@
470 self._detectEncoding(markup, isHTML)
471 self.smartQuotesTo = smartQuotesTo
472 self.triedEncodings = []
473 - if markup == '' or isinstance(markup, unicode):
474 + if markup == '' or isinstance(markup, str):
475 self.originalEncoding = None
476 - self.unicode = unicode(markup)
477 + self.str = str(markup)
481 @@ -1783,7 +1783,7 @@
484 # If no luck and we have auto-detection library, try that:
485 - if not u and chardet and not isinstance(self.markup, unicode):
486 + if not u and chardet and not isinstance(self.markup, str):
487 u = self._convertFrom(chardet.detect(self.markup)['encoding'])
489 # As a last resort, try utf-8 and windows-1252:
490 @@ -1792,7 +1792,7 @@
491 u = self._convertFrom(proposed_encoding)
496 if not u: self.originalEncoding = None
498 def _subMSChar(self, orig):
499 @@ -1819,7 +1819,7 @@
502 markup = re.compile("([\x80-\x9f])").sub \
503 - (lambda(x): self._subMSChar(x.group(1)),
504 + (lambda x: self._subMSChar(x.group(1)),
508 @@ -1827,7 +1827,7 @@
509 u = self._toUnicode(markup, proposed)
511 self.originalEncoding = proposed
512 - except Exception, e:
513 + except Exception as e:
514 # print "That didn't work!"
517 @@ -1856,7 +1856,7 @@
518 elif data[:4] == '\xff\xfe\x00\x00':
519 encoding = 'utf-32le'
521 - newdata = unicode(data, encoding)
522 + newdata = str(data, encoding)
525 def _detectEncoding(self, xml_data, isHTML=False):
526 @@ -1869,41 +1869,41 @@
527 elif xml_data[:4] == '\x00\x3c\x00\x3f':
529 sniffed_xml_encoding = 'utf-16be'
530 - xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
531 + xml_data = str(xml_data, 'utf-16be').encode('utf-8')
532 elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
533 and (xml_data[2:4] != '\x00\x00'):
535 sniffed_xml_encoding = 'utf-16be'
536 - xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
537 + xml_data = str(xml_data[2:], 'utf-16be').encode('utf-8')
538 elif xml_data[:4] == '\x3c\x00\x3f\x00':
540 sniffed_xml_encoding = 'utf-16le'
541 - xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
542 + xml_data = str(xml_data, 'utf-16le').encode('utf-8')
543 elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
544 (xml_data[2:4] != '\x00\x00'):
546 sniffed_xml_encoding = 'utf-16le'
547 - xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
548 + xml_data = str(xml_data[2:], 'utf-16le').encode('utf-8')
549 elif xml_data[:4] == '\x00\x00\x00\x3c':
551 sniffed_xml_encoding = 'utf-32be'
552 - xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
553 + xml_data = str(xml_data, 'utf-32be').encode('utf-8')
554 elif xml_data[:4] == '\x3c\x00\x00\x00':
556 sniffed_xml_encoding = 'utf-32le'
557 - xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
558 + xml_data = str(xml_data, 'utf-32le').encode('utf-8')
559 elif xml_data[:4] == '\x00\x00\xfe\xff':
561 sniffed_xml_encoding = 'utf-32be'
562 - xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
563 + xml_data = str(xml_data[4:], 'utf-32be').encode('utf-8')
564 elif xml_data[:4] == '\xff\xfe\x00\x00':
566 sniffed_xml_encoding = 'utf-32le'
567 - xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
568 + xml_data = str(xml_data[4:], 'utf-32le').encode('utf-8')
569 elif xml_data[:3] == '\xef\xbb\xbf':
571 sniffed_xml_encoding = 'utf-8'
572 - xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
573 + xml_data = str(xml_data[3:], 'utf-8').encode('utf-8')
575 sniffed_xml_encoding = 'ascii'
577 @@ -1966,7 +1966,7 @@
578 250,251,252,253,254,255)
580 c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
581 - ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
582 + ''.join(map(chr, list(range(256)))), ''.join(map(chr, emap)))
583 return s.translate(c.EBCDIC_TO_ASCII_MAP)
585 MS_CHARS = { '\x80' : ('euro', '20AC'),
586 @@ -2009,4 +2009,4 @@
587 if __name__ == '__main__':
589 soup = BeautifulSoup(sys.stdin)
590 - print soup.prettify()
591 + print(soup.prettify())
592 diff -Naur client175_0.7-original/cherrypy/cherryd client175_0.7/cherrypy/cherryd
593 --- client175_0.7-original/cherrypy/cherryd 2010-04-20 13:10:10.000000000 +0200
594 +++ client175_0.7/cherrypy/cherryd 2021-08-03 15:37:40.098963967 +0200
596 """Subscribe all engine plugins and start the engine."""
597 sys.path = [''] + sys.path
598 for i in imports or []:
599 - exec "import %s" % i
600 + exec("import %s" % i)
602 for c in configfiles or []:
603 cherrypy.config.update(c)
604 diff -Naur client175_0.7-original/cherrypy/_cpcgifs.py client175_0.7/cherrypy/_cpcgifs.py
605 --- client175_0.7-original/cherrypy/_cpcgifs.py 2010-04-20 13:10:10.000000000 +0200
606 +++ client175_0.7/cherrypy/_cpcgifs.py 2021-08-03 14:41:19.199896214 +0200
608 def __init__(self, *args, **kwds):
610 cgi.FieldStorage.__init__(self, *args, **kwds)
611 - except ValueError, ex:
612 + except ValueError as ex:
613 if str(ex) == 'Maximum content length exceeded':
614 raise cherrypy.HTTPError(status=413)
616 diff -Naur client175_0.7-original/cherrypy/_cpchecker.py client175_0.7/cherrypy/_cpchecker.py
617 --- client175_0.7-original/cherrypy/_cpchecker.py 2010-04-20 13:10:10.000000000 +0200
618 +++ client175_0.7/cherrypy/_cpchecker.py 2021-08-03 14:41:30.971721551 +0200
620 global_config_contained_paths = False
622 def check_skipped_app_config(self):
623 - for sn, app in cherrypy.tree.apps.iteritems():
624 + for sn, app in cherrypy.tree.apps.items():
625 if not isinstance(app, cherrypy.Application):
629 def check_static_paths(self):
630 # Use the dummy Request object in the main thread.
631 request = cherrypy.request
632 - for sn, app in cherrypy.tree.apps.iteritems():
633 + for sn, app in cherrypy.tree.apps.items():
634 if not isinstance(app, cherrypy.Application):
639 def _compat(self, config):
640 """Process config and warn on each obsolete or deprecated entry."""
641 - for section, conf in config.iteritems():
642 + for section, conf in config.items():
643 if isinstance(conf, dict):
644 - for k, v in conf.iteritems():
645 + for k, v in conf.items():
646 if k in self.obsolete:
647 warnings.warn("%r is obsolete. Use %r instead.\n"
650 def check_compatibility(self):
651 """Process config and warn on each obsolete or deprecated entry."""
652 self._compat(cherrypy.config)
653 - for sn, app in cherrypy.tree.apps.iteritems():
654 + for sn, app in cherrypy.tree.apps.items():
655 if not isinstance(app, cherrypy.Application):
657 self._compat(app.config)
658 @@ -164,16 +164,16 @@
660 def _known_ns(self, app):
662 - ns.extend(app.toolboxes.keys())
663 - ns.extend(app.namespaces.keys())
664 - ns.extend(app.request_class.namespaces.keys())
665 - ns.extend(cherrypy.config.namespaces.keys())
666 + ns.extend(list(app.toolboxes.keys()))
667 + ns.extend(list(app.namespaces.keys()))
668 + ns.extend(list(app.request_class.namespaces.keys()))
669 + ns.extend(list(cherrypy.config.namespaces.keys()))
670 ns += self.extra_config_namespaces
672 - for section, conf in app.config.iteritems():
673 + for section, conf in app.config.items():
674 is_path_section = section.startswith("/")
675 if is_path_section and isinstance(conf, dict):
676 - for k, v in conf.iteritems():
677 + for k, v in conf.items():
680 if atoms[0] not in ns:
683 def check_config_namespaces(self):
684 """Process config and warn on each unknown config namespace."""
685 - for sn, app in cherrypy.tree.apps.iteritems():
686 + for sn, app in cherrypy.tree.apps.items():
687 if not isinstance(app, cherrypy.Application):
691 known_config_types = {}
693 def _populate_known_types(self):
695 - builtins = [x for x in vars(__builtin__).values()
697 + builtins = [x for x in list(vars(__builtin__).values())
698 if type(x) is type(str)]
700 def traverse(obj, namespace):
702 msg = ("The config entry %r in section %r is of type %r, "
703 "which does not match the expected type %r.")
705 - for section, conf in config.iteritems():
706 + for section, conf in config.items():
707 if isinstance(conf, dict):
708 - for k, v in conf.iteritems():
709 + for k, v in conf.items():
711 expected_type = self.known_config_types.get(k, None)
714 def check_config_types(self):
715 """Assert that config values are of the same type as default values."""
716 self._known_types(cherrypy.config)
717 - for sn, app in cherrypy.tree.apps.iteritems():
718 + for sn, app in cherrypy.tree.apps.items():
719 if not isinstance(app, cherrypy.Application):
721 self._known_types(app.config)
724 def check_localhost(self):
725 """Warn if any socket_host is 'localhost'. See #711."""
726 - for k, v in cherrypy.config.iteritems():
727 + for k, v in cherrypy.config.items():
728 if k == 'server.socket_host' and v == 'localhost':
729 warnings.warn("The use of 'localhost' as a socket host can "
730 "cause problems on newer systems, since 'localhost' can "
731 diff -Naur client175_0.7-original/cherrypy/_cpconfig.py client175_0.7/cherrypy/_cpconfig.py
732 --- client175_0.7-original/cherrypy/_cpconfig.py 2010-04-20 13:10:10.000000000 +0200
733 +++ client175_0.7/cherrypy/_cpconfig.py 2021-08-03 14:41:39.459596077 +0200
735 style) context manager.
746 """Return a dict from 'config' whether it is a dict, file, or filename."""
747 - if isinstance(config, basestring):
748 + if isinstance(config, str):
749 config = _Parser().dict_from_file(config)
750 elif hasattr(config, 'read'):
751 config = _Parser().dict_from_file(config)
752 @@ -150,11 +150,11 @@
753 If the given config is a filename, it will be appended to
754 the list of files to monitor for "autoreload" changes.
756 - if isinstance(other, basestring):
757 + if isinstance(other, str):
758 cherrypy.engine.autoreload.files.add(other)
760 # Load other into base
761 - for section, value_map in as_dict(other).iteritems():
762 + for section, value_map in as_dict(other).items():
763 base.setdefault(section, {}).update(value_map)
766 @@ -196,14 +196,14 @@
767 # with handler as callable:
768 # for k, v in ns_confs.get(ns, {}).iteritems():
770 - for ns, handler in self.iteritems():
771 + for ns, handler in self.items():
772 exit = getattr(handler, "__exit__", None)
774 callable = handler.__enter__()
778 - for k, v in ns_confs.get(ns, {}).iteritems():
779 + for k, v in ns_confs.get(ns, {}).items():
782 # The exceptional case is handled here
785 exit(None, None, None)
787 - for k, v in ns_confs.get(ns, {}).iteritems():
788 + for k, v in ns_confs.get(ns, {}).items():
794 def update(self, config):
795 """Update self from a dict, file or filename."""
796 - if isinstance(config, basestring):
797 + if isinstance(config, str):
799 cherrypy.engine.autoreload.files.add(config)
800 config = _Parser().dict_from_file(config)
802 Config.namespaces["tree"] = _tree_namespace_handler
805 -class _Parser(ConfigParser.ConfigParser):
806 +class _Parser(configparser.ConfigParser):
807 """Sub-class of ConfigParser that keeps the case of options and that raises
808 an exception if the file cannot be read.
813 def read(self, filenames):
814 - if isinstance(filenames, basestring):
815 + if isinstance(filenames, str):
816 filenames = [filenames]
817 for filename in filenames:
820 value = self.get(section, option, raw, vars)
822 value = unrepr(value)
823 - except Exception, x:
824 + except Exception as x:
825 msg = ("Config error in section: %r, option: %r, "
826 "value: %r. Config values must be valid Python." %
827 (section, option, value))
828 diff -Naur client175_0.7-original/cherrypy/_cpdispatch.py client175_0.7/cherrypy/_cpdispatch.py
829 --- client175_0.7-original/cherrypy/_cpdispatch.py 2010-04-20 13:10:10.000000000 +0200
830 +++ client175_0.7/cherrypy/_cpdispatch.py 2021-08-03 14:41:48.627460479 +0200
834 return self.callable(*self.args, **self.kwargs)
835 - except TypeError, x:
836 + except TypeError as x:
837 test_callable_spec(self.callable, self.args, self.kwargs)
844 - for key in callable_kwargs.keys():
845 + for key in list(callable_kwargs.keys()):
853 - for key, usage in arg_usage.iteritems():
854 + for key, usage in arg_usage.items():
856 missing_args.append(key)
860 # Try successive objects (reverse order)
861 num_candidates = len(object_trail) - 1
862 - for i in xrange(num_candidates, -1, -1):
863 + for i in range(num_candidates, -1, -1):
865 name, candidate, nodeconf, curpath = object_trail[i]
866 if candidate is None:
867 diff -Naur client175_0.7-original/cherrypy/_cperror.py client175_0.7/cherrypy/_cperror.py
868 --- client175_0.7-original/cherrypy/_cperror.py 2010-04-20 13:10:10.000000000 +0200
869 +++ client175_0.7/cherrypy/_cperror.py 2021-08-03 14:41:56.939337474 +0200
871 from cgi import escape as _escape
872 from sys import exc_info as _exc_info
873 from traceback import format_exception as _format_exception
874 -from urlparse import urljoin as _urljoin
875 +from urllib.parse import urljoin as _urljoin
876 from cherrypy.lib import http as _http
881 request = cherrypy.request
883 - if isinstance(urls, basestring):
884 + if isinstance(urls, str):
889 for key in ["Accept-Ranges", "Age", "ETag", "Location", "Retry-After",
890 "Vary", "Content-Encoding", "Content-Length", "Expires",
891 "Content-Location", "Content-MD5", "Last-Modified"]:
892 - if respheaders.has_key(key):
893 + if key in respheaders:
898 # specifies the current length of the selected resource.
899 # A response with status code 206 (Partial Content) MUST NOT
900 # include a Content-Range field with a byte-range- resp-spec of "*".
901 - if respheaders.has_key("Content-Range"):
902 + if "Content-Range" in respheaders:
903 del respheaders["Content-Range"]
909 code, reason, message = _http.valid_status(status)
910 - except ValueError, x:
911 + except ValueError as x:
912 raise cherrypy.HTTPError(500, x.args[0])
914 # We can't use setdefault here, because some
916 if kwargs.get('version') is None:
917 kwargs['version'] = cherrypy.__version__
919 - for k, v in kwargs.iteritems():
920 + for k, v in kwargs.items():
924 diff -Naur client175_0.7-original/cherrypy/_cplogging.py client175_0.7/cherrypy/_cplogging.py
925 --- client175_0.7-original/cherrypy/_cplogging.py 2010-04-20 13:10:10.000000000 +0200
926 +++ client175_0.7/cherrypy/_cplogging.py 2021-08-03 14:42:04.739222052 +0200
928 'f': inheaders.get('Referer', ''),
929 'a': inheaders.get('User-Agent', ''),
931 - for k, v in atoms.items():
932 - if isinstance(v, unicode):
933 + for k, v in list(atoms.items()):
934 + if isinstance(v, str):
936 elif not isinstance(v, str):
938 diff -Naur client175_0.7-original/cherrypy/_cpmodpy.py client175_0.7/cherrypy/_cpmodpy.py
939 --- client175_0.7-original/cherrypy/_cpmodpy.py 2010-04-20 13:10:10.000000000 +0200
940 +++ client175_0.7/cherrypy/_cpmodpy.py 2021-08-03 14:42:11.807117510 +0200
949 from cherrypy._cperror import format_exc, bare_error
953 reqproto = req.protocol
954 - headers = req.headers_in.items()
955 + headers = list(req.headers_in.items())
956 rfile = _ReadOnlyRequest(req)
961 request.run(method, path, qs, reqproto, headers, rfile)
963 - except cherrypy.InternalRedirect, ir:
964 + except cherrypy.InternalRedirect as ir:
965 app.release_serving()
972 - rfile = StringIO.StringIO()
973 + rfile = io.StringIO()
975 send_response(req, response.status, response.header_list,
976 response.body, response.stream)
981 - if isinstance(body, basestring):
982 + if isinstance(body, str):
986 diff -Naur client175_0.7-original/cherrypy/_cprequest.py client175_0.7/cherrypy/_cprequest.py
987 --- client175_0.7-original/cherrypy/_cprequest.py 2010-04-20 13:10:10.000000000 +0200
988 +++ client175_0.7/cherrypy/_cprequest.py 2021-08-03 14:42:19.091009678 +0200
997 from cherrypy.lib import http, file_generator
1000 -class Hook(object):
1001 +class Hook(object, metaclass=cherrypy._AttributeDocstrings):
1002 """A callback and its metadata: failsafe, priority, and kwargs."""
1004 - __metaclass__ = cherrypy._AttributeDocstrings
1008 The bare callable that this Hook object is wrapping, which will
1010 % (cls.__module__, cls.__name__, self.callback,
1011 self.failsafe, self.priority,
1012 ", ".join(['%s=%r' % (k, v)
1013 - for k, v in self.kwargs.iteritems()])))
1014 + for k, v in self.kwargs.items()])))
1017 class HookMap(dict):
1018 @@ -111,14 +109,14 @@
1019 newmap = self.__class__()
1020 # We can't just use 'update' because we want copies of the
1021 # mutable values (each is a list) as well.
1022 - for k, v in self.iteritems():
1023 + for k, v in self.items():
1029 cls = self.__class__
1030 - return "%s.%s(points=%r)" % (cls.__module__, cls.__name__, self.keys())
1031 + return "%s.%s(points=%r)" % (cls.__module__, cls.__name__, list(self.keys()))
1034 # Config namespace handlers
1036 # hookpoint per path (e.g. "hooks.before_handler.1").
1037 # Little-known fact you only get from reading source ;)
1038 hookpoint = k.split(".", 1)[0]
1039 - if isinstance(v, basestring):
1040 + if isinstance(v, str):
1041 v = cherrypy.lib.attributes(v)
1042 if not isinstance(v, Hook):
1045 'before_error_response', 'after_error_response']
1048 -class Request(object):
1049 +class Request(object, metaclass=cherrypy._AttributeDocstrings):
1052 This object represents the metadata of an HTTP request message;
1054 the given URL, and the execution plan for generating a response.
1057 - __metaclass__ = cherrypy._AttributeDocstrings
1061 The previous Request object (if any). This should be None
1063 values (decoded according to RFC 2047 if necessary). See also:
1064 http.HeaderMap, http.HeaderElement."""
1066 - cookie = Cookie.SimpleCookie()
1067 + cookie = http.cookies.SimpleCookie()
1068 cookie__doc = """See help(Cookie)."""
1072 self.header_list = list(headers)
1074 self.headers = http.HeaderMap()
1075 - self.cookie = Cookie.SimpleCookie()
1076 + self.cookie = http.cookies.SimpleCookie()
1079 # path_info should be the path from the
1081 self.stage = 'before_finalize'
1082 self.hooks.run('before_finalize')
1083 cherrypy.response.finalize()
1084 - except (cherrypy.HTTPRedirect, cherrypy.HTTPError), inst:
1085 + except (cherrypy.HTTPRedirect, cherrypy.HTTPError) as inst:
1087 self.stage = 'before_finalize (HTTPError)'
1088 self.hooks.run('before_finalize')
1090 if name == 'Cookie':
1092 self.cookie.load(value)
1093 - except Cookie.CookieError:
1094 + except http.cookies.CookieError:
1095 msg = "Illegal cookie name %s" % value.split('=')[0]
1096 raise cherrypy.HTTPError(400, msg)
1099 # won't parse the request body for params if the client
1100 # didn't provide a "Content-Type" header.
1101 if 'Content-Type' not in self.headers:
1102 - h = http.HeaderMap(self.headers.items())
1103 + h = http.HeaderMap(list(self.headers.items()))
1104 h['Content-Type'] = ''
1108 # FieldStorage only recognizes POST.
1109 environ={'REQUEST_METHOD': "POST"},
1110 keep_blank_values=1)
1111 - except Exception, e:
1112 + except Exception as e:
1113 if e.__class__.__name__ == 'MaxSizeExceeded':
1114 # Post data is too big
1115 raise cherrypy.HTTPError(413)
1117 self.error_response()
1118 self.hooks.run("after_error_response")
1119 cherrypy.response.finalize()
1120 - except cherrypy.HTTPRedirect, inst:
1121 + except cherrypy.HTTPRedirect as inst:
1123 cherrypy.response.finalize()
1127 def __set__(self, obj, value):
1128 # Convert the given value to an iterable object.
1129 - if isinstance(value, basestring):
1130 + if isinstance(value, str):
1131 # strings get wrapped in a list because iterating over a single
1132 # item list is much faster than iterating over every character
1138 -class Response(object):
1139 +class Response(object, metaclass=cherrypy._AttributeDocstrings):
1140 """An HTTP Response, including status, headers, and body.
1142 Application developers should use Response.headers (a dict) to
1144 (key, value) tuples.
1147 - __metaclass__ = cherrypy._AttributeDocstrings
1149 # Class attributes for dev-time introspection.
1151 status__doc = """The HTTP Status-Code and Reason-Phrase."""
1153 values (decoded according to RFC 2047 if necessary). See also:
1154 http.HeaderMap, http.HeaderElement."""
1156 - cookie = Cookie.SimpleCookie()
1157 + cookie = http.cookies.SimpleCookie()
1158 cookie__doc = """See help(Cookie)."""
1162 "Server": "CherryPy/" + cherrypy.__version__,
1163 "Date": http.HTTPDate(self.time),
1165 - self.cookie = Cookie.SimpleCookie()
1166 + self.cookie = http.cookies.SimpleCookie()
1168 def collapse_body(self):
1169 """Collapse self.body to a single string; replace it and return it."""
1171 """Transform headers (and cookies) into self.header_list. (Core)"""
1173 code, reason, _ = http.valid_status(self.status)
1174 - except ValueError, x:
1175 + except ValueError as x:
1176 raise cherrypy.HTTPError(500, x.args[0])
1178 self.status = "%s %s" % (code, reason)
1179 diff -Naur client175_0.7-original/cherrypy/_cpserver.py client175_0.7/cherrypy/_cpserver.py
1180 --- client175_0.7-original/cherrypy/_cpserver.py 2010-04-20 13:10:10.000000000 +0200
1181 +++ client175_0.7/cherrypy/_cpserver.py 2021-08-03 14:42:27.582884114 +0200
1183 if httpserver is None:
1184 from cherrypy import _cpwsgi_server
1185 httpserver = _cpwsgi_server.CPWSGIServer()
1186 - if isinstance(httpserver, basestring):
1187 + if isinstance(httpserver, str):
1188 httpserver = attributes(httpserver)()
1190 if self.socket_file:
1191 diff -Naur client175_0.7-original/cherrypy/_cptools.py client175_0.7/cherrypy/_cptools.py
1192 --- client175_0.7-original/cherrypy/_cptools.py 2010-04-20 13:10:10.000000000 +0200
1193 +++ client175_0.7/cherrypy/_cptools.py 2021-08-03 14:43:38.721831788 +0200
1195 # Use this instead of importing inspect for less mem overhead.
1197 if isinstance(func, types.MethodType):
1198 - func = func.im_func
1199 - co = func.func_code
1200 + func = func.__func__
1201 + co = func.__code__
1202 return co.co_varnames[:co.co_argcount]
1207 subspace = self.namespace + "." + self._name + "."
1208 f._cp_config[subspace + "on"] = True
1209 - for k, v in kwargs.iteritems():
1210 + for k, v in kwargs.items():
1211 f._cp_config[subspace + k] = v
1213 return tool_decorator
1217 # Grab cookie-relevant tool args
1218 - conf = dict([(k, v) for k, v in self._merged_args().iteritems()
1219 + conf = dict([(k, v) for k, v in self._merged_args().items()
1220 if k in ('path', 'path_header', 'name', 'timeout',
1221 'domain', 'secure')])
1222 _sessions.set_response_cookie(**conf)
1224 # if a method is not found, an xmlrpclib.Fault should be returned
1225 # raising an exception here will do that; see
1226 # cherrypy.lib.xmlrpc.on_error
1227 - raise Exception, 'method "%s" is not supported' % attr
1228 + raise Exception('method "%s" is not supported' % attr)
1230 conf = cherrypy.request.toolmaps['tools'].get("xmlrpc", {})
1231 _xmlrpc.respond(body,
1233 cherrypy._cache = kwargs.pop("cache_class", _caching.MemoryCache)()
1235 # Take all remaining kwargs and set them on the Cache object.
1236 - for k, v in kwargs.iteritems():
1237 + for k, v in kwargs.items():
1238 setattr(cherrypy._cache, k, v)
1240 if _caching.get(invalid_methods=invalid_methods):
1242 """Run tool._setup() for each tool in our toolmap."""
1243 map = cherrypy.request.toolmaps.get(self.namespace)
1245 - for name, settings in map.items():
1246 + for name, settings in list(map.items()):
1247 if settings.get("on", False):
1248 tool = getattr(self, name)
1250 diff -Naur client175_0.7-original/cherrypy/_cptree.py client175_0.7/cherrypy/_cptree.py
1251 --- client175_0.7-original/cherrypy/_cptree.py 2010-04-20 13:10:10.000000000 +0200
1252 +++ client175_0.7/cherrypy/_cptree.py 2021-08-03 14:43:50.457658068 +0200
1254 from cherrypy.lib import http as _http
1257 -class Application(object):
1258 +class Application(object, metaclass=cherrypy._AttributeDocstrings):
1259 """A CherryPy Application.
1261 Servers and gateways should not instantiate Request objects directly.
1263 (WSGI application object) for itself.
1266 - __metaclass__ = cherrypy._AttributeDocstrings
1270 The top-most container of page handlers for this app. Handlers should
1272 req = self.request_class(local, remote, scheme, sproto)
1275 - for name, toolbox in self.toolboxes.iteritems():
1276 + for name, toolbox in self.toolboxes.items():
1277 req.namespaces[name] = toolbox
1279 resp = self.response_class()
1281 if isinstance(root, Application):
1283 if script_name != "" and script_name != app.script_name:
1284 - raise ValueError, "Cannot specify a different script name and pass an Application instance to cherrypy.mount"
1285 + raise ValueError("Cannot specify a different script name and pass an Application instance to cherrypy.mount")
1286 script_name = app.script_name
1288 app = Application(root, script_name)
1289 diff -Naur client175_0.7-original/cherrypy/_cpwsgi.py client175_0.7/cherrypy/_cpwsgi.py
1290 --- client175_0.7-original/cherrypy/_cpwsgi.py 2010-04-20 13:10:10.000000000 +0200
1291 +++ client175_0.7/cherrypy/_cpwsgi.py 2021-08-03 14:44:08.117396886 +0200
1293 """WSGI interface (see PEP 333)."""
1295 -import StringIO as _StringIO
1296 +import io as _StringIO
1299 import cherrypy as _cherrypy
1304 - except _cherrypy.InternalRedirect, ir:
1305 + except _cherrypy.InternalRedirect as ir:
1306 self.environ['cherrypy.previous_request'] = _cherrypy.serving.request
1308 self.iredirect(ir.path, ir.query_string)
1314 + def __next__(self):
1316 - chunk = self.iter_response.next()
1317 + chunk = next(self.iter_response)
1318 # WSGI requires all data to be of type "str". This coercion should
1319 # not take any time at all if chunk is already of type "str".
1320 # If it's unicode, it could be a big performance hit (x ~500).
1325 - except _cherrypy.InternalRedirect, ir:
1326 + except _cherrypy.InternalRedirect as ir:
1327 self.environ['cherrypy.previous_request'] = _cherrypy.serving.request
1329 self.iredirect(ir.path, ir.query_string)
1330 diff -Naur client175_0.7-original/cherrypy/__init__.py client175_0.7/cherrypy/__init__.py
1331 --- client175_0.7-original/cherrypy/__init__.py 2010-04-20 13:10:10.000000000 +0200
1332 +++ client175_0.7/cherrypy/__init__.py 2021-08-03 14:44:38.280950778 +0200
1335 __version__ = "3.1.2"
1337 -from urlparse import urljoin as _urljoin
1338 +from urllib.parse import urljoin as _urljoin
1341 class _AttributeDocstrings(type):
1344 newdoc = [cls.__doc__ or ""]
1346 - dctnames = dct.keys()
1347 + dctnames = list(dct.keys())
1350 for name in dctnames:
1353 from cherrypy._cpthreadinglocal import local as _local
1355 -class _Serving(_local):
1356 +class _Serving(_local, metaclass=_AttributeDocstrings):
1357 """An interface for registering request and response objects.
1359 Rather than have a separate "thread local" object for the request and
1364 - __metaclass__ = _AttributeDocstrings
1366 request = _cprequest.Request(_http.Host("127.0.0.1", 80),
1367 _http.Host("127.0.0.1", 1111))
1370 child = getattr(serving, self.__attrname__)
1373 - def __nonzero__(self):
1374 + def __bool__(self):
1375 child = getattr(serving, self.__attrname__)
1381 if alias is not None:
1382 - if isinstance(alias, basestring):
1383 + if isinstance(alias, str):
1384 parents[alias.replace(".", "_")] = func
1387 diff -Naur client175_0.7-original/cherrypy/lib/auth.py client175_0.7/cherrypy/lib/auth.py
1388 --- client175_0.7-original/cherrypy/lib/auth.py 2010-04-20 13:10:10.000000000 +0200
1389 +++ client175_0.7/cherrypy/lib/auth.py 2021-08-03 14:45:01.296612330 +0200
1391 users = users() # expect it to return a dictionary
1393 if not isinstance(users, dict):
1394 - raise ValueError, "Authentication users must be a dictionary"
1395 + raise ValueError("Authentication users must be a dictionary")
1397 # fetch the user password
1398 password = users.get(ah["username"], None)
1400 password = users(ah["username"])
1402 if not isinstance(users, dict):
1403 - raise ValueError, "Authentication users must be a dictionary"
1404 + raise ValueError("Authentication users must be a dictionary")
1406 # fetch the user password
1407 password = users.get(ah["username"], None)
1408 diff -Naur client175_0.7-original/cherrypy/lib/caching.py client175_0.7/cherrypy/lib/caching.py
1409 --- client175_0.7-original/cherrypy/lib/caching.py 2010-04-20 13:10:10.000000000 +0200
1410 +++ client175_0.7/cherrypy/lib/caching.py 2021-08-03 14:45:08.464504417 +0200
1412 # See tickets #99 and #180 for more information.
1415 - for expiration_time, objects in self.expirations.items():
1416 + for expiration_time, objects in list(self.expirations.items()):
1417 if expiration_time <= now:
1418 for obj_size, obj_key in objects:
1421 # this was put into the cached copy, and should have been
1422 # resurrected just above (response.headers = cache_data[1]).
1423 cptools.validate_since()
1424 - except cherrypy.HTTPRedirect, x:
1425 + except cherrypy.HTTPRedirect as x:
1427 cherrypy._cache.tot_non_modified += 1
1430 cherrypy.response.headers.elements('Vary')]
1432 sel_headers = dict([(k, v) for k, v
1433 - in cherrypy.request.headers.iteritems()
1434 + in cherrypy.request.headers.items()
1438 diff -Naur client175_0.7-original/cherrypy/lib/covercp.py client175_0.7/cherrypy/lib/covercp.py
1439 --- client175_0.7-original/cherrypy/lib/covercp.py 2010-04-20 13:10:10.000000000 +0200
1440 +++ client175_0.7/cherrypy/lib/covercp.py 2021-08-03 14:45:14.876409627 +0200
1446 +import urllib.request, urllib.parse, urllib.error
1448 localFile = os.path.join(os.path.dirname(__file__), "coverage.cache")
1451 - import cStringIO as StringIO
1452 + import io as StringIO
1458 from coverage import the_coverage as coverage
1460 def _show_branch(root, base, path, pct=0, showpct=False, exclude=""):
1462 # Show the directory name and any of our children
1463 - dirs = [k for k, v in root.iteritems() if v]
1464 + dirs = [k for k, v in root.items() if v]
1467 newpath = os.path.join(path, name)
1469 relpath = newpath[len(base):]
1470 yield "| " * relpath.count(os.sep)
1471 yield "<a class='directory' href='menu?base=%s&exclude=%s'>%s</a>\n" % \
1472 - (newpath, urllib.quote_plus(exclude), name)
1473 + (newpath, urllib.parse.quote_plus(exclude), name)
1475 for chunk in _show_branch(root[name], base, newpath, pct, showpct, exclude):
1478 # Now list the files
1479 if path.lower().startswith(base):
1480 relpath = path[len(base):]
1481 - files = [k for k, v in root.iteritems() if not v]
1482 + files = [k for k, v in root.items() if not v]
1485 newpath = os.path.join(path, name)
1487 """Return covered module names as a nested dict."""
1489 coverage.get_ready()
1490 - runs = coverage.cexecuted.keys()
1491 + runs = list(coverage.cexecuted.keys())
1494 if not _skip_file(path, exclude) and not os.path.isdir(path):
1497 path += atom + os.sep
1498 yield ("<a href='menu?base=%s&exclude=%s'>%s</a> %s"
1499 - % (path, urllib.quote_plus(exclude), atom, os.sep))
1500 + % (path, urllib.parse.quote_plus(exclude), atom, os.sep))
1503 yield "<div id='tree'>"
1504 diff -Naur client175_0.7-original/cherrypy/lib/cptools.py client175_0.7/cherrypy/lib/cptools.py
1505 --- client175_0.7-original/cherrypy/lib/cptools.py 2010-04-20 13:10:10.000000000 +0200
1506 +++ client175_0.7/cherrypy/lib/cptools.py 2021-08-03 14:45:22.384298594 +0200
1509 body = self.login_screen(from_page, username, error_msg)
1510 cherrypy.response.body = body
1511 - if cherrypy.response.headers.has_key("Content-Length"):
1512 + if "Content-Length" in cherrypy.response.headers:
1513 # Delete Content-Length header so finalize() recalcs it.
1514 del cherrypy.response.headers["Content-Length"]
1517 sess[self.session_key] = username = self.anonymous()
1519 cherrypy.response.body = self.login_screen(cherrypy.url(qs=request.query_string))
1520 - if cherrypy.response.headers.has_key("Content-Length"):
1521 + if "Content-Length" in cherrypy.response.headers:
1522 # Delete Content-Length header so finalize() recalcs it.
1523 del cherrypy.response.headers["Content-Length"]
1527 def session_auth(**kwargs):
1529 - for k, v in kwargs.iteritems():
1530 + for k, v in kwargs.items():
1533 session_auth.__doc__ = """Session authentication hook.
1535 # Sort by the standard points if possible.
1536 from cherrypy import _cprequest
1537 points = _cprequest.hookpoints
1538 - for k in cherrypy.request.hooks.keys():
1539 + for k in list(cherrypy.request.hooks.keys()):
1547 - if isinstance(media, basestring):
1548 + if isinstance(media, str):
1551 # Parse the Accept request header, and try to match one
1552 diff -Naur client175_0.7-original/cherrypy/lib/encoding.py client175_0.7/cherrypy/lib/encoding.py
1553 --- client175_0.7-original/cherrypy/lib/encoding.py 2010-04-20 13:10:10.000000000 +0200
1554 +++ client175_0.7/cherrypy/lib/encoding.py 2021-08-03 14:45:29.700190398 +0200
1557 def decode_params(encoding):
1559 - for key, value in cherrypy.request.params.items():
1560 + for key, value in list(cherrypy.request.params.items()):
1561 if not hasattr(value, 'file'):
1562 # Skip the value if it is an uploaded file
1563 if isinstance(value, list):
1568 - if isinstance(chunk, unicode):
1569 + if isinstance(chunk, str):
1570 chunk = chunk.encode(encoding, errors)
1572 cherrypy.response.body = encoder(cherrypy.response.body)
1576 for chunk in cherrypy.response.body:
1577 - if isinstance(chunk, unicode):
1578 + if isinstance(chunk, str):
1579 chunk = chunk.encode(encoding, errors)
1581 cherrypy.response.body = body
1584 response.collapse_body()
1585 encoder = encode_string
1586 - if response.headers.has_key("Content-Length"):
1587 + if "Content-Length" in response.headers:
1588 # Delete Content-Length header so finalize() recalcs it.
1589 # Encoded strings may be of different lengths from their
1590 # unicode equivalents, and even from each other. For example:
1592 yield '\037\213' # magic header
1593 yield '\010' # compression method
1595 - yield struct.pack("<L", long(time.time()))
1596 + yield struct.pack("<L", int(time.time()))
1600 @@ -194,12 +194,12 @@
1601 yield zobj.compress(line)
1603 yield struct.pack("<l", crc)
1604 - yield struct.pack("<L", size & 0xFFFFFFFFL)
1605 + yield struct.pack("<L", size & 0xFFFFFFFF)
1607 def decompress(body):
1608 - import gzip, StringIO
1611 - zbuf = StringIO.StringIO()
1612 + zbuf = io.StringIO()
1615 zfile = gzip.GzipFile(mode='rb', fileobj=zbuf)
1618 response.headers['Content-Encoding'] = 'gzip'
1619 response.body = compress(response.body, compress_level)
1620 - if response.headers.has_key("Content-Length"):
1621 + if "Content-Length" in response.headers:
1622 # Delete Content-Length header so finalize() recalcs it.
1623 del response.headers["Content-Length"]
1625 diff -Naur client175_0.7-original/cherrypy/lib/httpauth.py client175_0.7/cherrypy/lib/httpauth.py
1626 --- client175_0.7-original/cherrypy/lib/httpauth.py 2010-04-20 13:10:10.000000000 +0200
1627 +++ client175_0.7/cherrypy/lib/httpauth.py 2021-08-03 14:45:46.595938962 +0200
1633 +import urllib.request, urllib.error, urllib.parse
1636 MD5_SESS = "MD5-sess"
1637 @@ -144,17 +144,17 @@
1638 # Check for required parameters
1639 required = ["username", "realm", "nonce", "uri", "response"]
1641 - if not params.has_key(k):
1642 + if k not in params:
1645 # If qop is sent then cnonce and nc MUST be present
1646 - if params.has_key("qop") and not (params.has_key("cnonce") \
1647 - and params.has_key("nc")):
1648 + if "qop" in params and not ("cnonce" in params \
1649 + and "nc" in params):
1652 # If qop is not sent, neither cnonce nor nc can be present
1653 - if (params.has_key("cnonce") or params.has_key("nc")) and \
1654 - not params.has_key("qop"):
1655 + if ("cnonce" in params or "nc" in params) and \
1656 + "qop" not in params:
1660 diff -Naur client175_0.7-original/cherrypy/lib/http.py client175_0.7/cherrypy/lib/http.py
1661 --- client175_0.7-original/cherrypy/lib/http.py 2010-04-20 13:10:10.000000000 +0200
1662 +++ client175_0.7/cherrypy/lib/http.py 2021-08-03 14:45:40.288033948 +0200
1664 # FuManChu will personally hang you up by your thumbs and submit you
1665 # to a public caning.
1667 -from BaseHTTPServer import BaseHTTPRequestHandler
1668 +from http.server import BaseHTTPRequestHandler
1669 response_codes = BaseHTTPRequestHandler.responses.copy()
1671 # From http://www.cherrypy.org/ticket/361
1675 stop = content_length - 1
1676 - start, stop = map(int, (start, stop))
1677 + start, stop = list(map(int, (start, stop)))
1678 if start >= content_length:
1679 # From rfc 2616 sec 14.16:
1680 # "If the server receives a request (other than one
1682 self.params = params
1684 def __unicode__(self):
1685 - p = [";%s=%s" % (k, v) for k, v in self.params.iteritems()]
1686 - return u"%s%s" % (self.value, "".join(p))
1687 + p = [";%s=%s" % (k, v) for k, v in self.params.items()]
1688 + return "%s%s" % (self.value, "".join(p))
1691 return str(self.__unicode__())
1692 @@ -264,14 +264,14 @@
1693 pm = {'x': int(pm[0]), 'y': int(pm[1])}
1695 pm = cgi.parse_qs(query_string, keep_blank_values)
1696 - for key, val in pm.items():
1697 + for key, val in list(pm.items()):
1702 def params_from_CGI_form(form):
1704 - for key in form.keys():
1705 + for key in list(form.keys()):
1706 value_list = form[key]
1707 if isinstance(value_list, list):
1710 return dict.has_key(self, str(key).title())
1712 def update(self, E):
1713 - for k in E.keys():
1714 + for k in list(E.keys()):
1715 self[str(k).title()] = E[k]
1717 def fromkeys(cls, seq, value=None):
1719 def output(self, protocol=(1, 1)):
1720 """Transform self into a list of (name, value) tuples."""
1722 - for key, v in self.iteritems():
1723 - if isinstance(v, unicode):
1724 + for key, v in self.items():
1725 + if isinstance(v, str):
1726 # HTTP/1.0 says, "Words of *TEXT may contain octets
1727 # from character sets other than US-ASCII." and
1728 # "Recipients of header field TEXT containing octets
1729 diff -Naur client175_0.7-original/cherrypy/lib/__init__.py client175_0.7/cherrypy/lib/__init__.py
1730 --- client175_0.7-original/cherrypy/lib/__init__.py 2010-04-20 13:10:10.000000000 +0200
1731 +++ client175_0.7/cherrypy/lib/__init__.py 2021-08-03 14:46:02.407667654 +0200
1733 """Load a module and retrieve an attribute of that module."""
1735 # Parse out the path, module, and attribute
1736 - last_dot = full_attribute_name.rfind(u".")
1737 + last_dot = full_attribute_name.rfind(".")
1738 attr_name = full_attribute_name[last_dot + 1:]
1739 mod_path = full_attribute_name[:last_dot]
1744 def build_CallFunc(self, o):
1745 - children = map(self.build, o.getChildren())
1746 + children = list(map(self.build, o.getChildren()))
1747 callee = children.pop(0)
1748 kwargs = children.pop() or {}
1749 starargs = children.pop() or ()
1751 return callee(*args, **kwargs)
1753 def build_List(self, o):
1754 - return map(self.build, o.getChildren())
1755 + return list(map(self.build, o.getChildren()))
1757 def build_Const(self, o):
1761 i = iter(map(self.build, o.getChildren()))
1767 def build_Tuple(self, o):
1770 # See if the Name is in __builtin__.
1772 - import __builtin__
1774 return getattr(__builtin__, o.name)
1775 except AttributeError:
1778 raise TypeError("unrepr could not resolve the name %s" % repr(o.name))
1780 def build_Add(self, o):
1781 - left, right = map(self.build, o.getChildren())
1782 + left, right = list(map(self.build, o.getChildren()))
1785 def build_Getattr(self, o):
1786 diff -Naur client175_0.7-original/cherrypy/lib/profiler.py client175_0.7/cherrypy/lib/profiler.py
1787 --- client175_0.7-original/cherrypy/lib/profiler.py 2010-04-20 13:10:10.000000000 +0200
1788 +++ client175_0.7/cherrypy/lib/profiler.py 2021-08-03 14:46:29.643218230 +0200
1793 - import cStringIO as StringIO
1794 + import io as StringIO
1803 def stats(self, filename, sortby='cumulative'):
1804 """stats(index) -> output of print_stats() for the given profile."""
1805 - sio = StringIO.StringIO()
1806 + sio = io.StringIO()
1807 if sys.version_info >= (2, 5):
1808 s = pstats.Stats(os.path.join(self.path, filename), stream=sio)
1810 diff -Naur client175_0.7-original/cherrypy/lib/safemime.py client175_0.7/cherrypy/lib/safemime.py
1811 --- client175_0.7-original/cherrypy/lib/safemime.py 2010-04-20 13:10:10.000000000 +0200
1812 +++ client175_0.7/cherrypy/lib/safemime.py 2021-08-03 14:46:40.883037698 +0200
1818 + def __next__(self):
1820 # Return '' if we've read all the data.
1821 if self.bytes_read >= self.clen:
1824 - data = self.rfile.next()
1825 + data = next(self.rfile)
1826 self.bytes_read += len(data)
1829 diff -Naur client175_0.7-original/cherrypy/lib/sessions.py client175_0.7/cherrypy/lib/sessions.py
1830 --- client175_0.7-original/cherrypy/lib/sessions.py 2010-04-20 13:10:10.000000000 +0200
1831 +++ client175_0.7/cherrypy/lib/sessions.py 2021-08-03 14:46:48.498916658 +0200
1836 - import cPickle as pickle
1837 + import pickle as pickle
1845 -class Session(object):
1846 +class Session(object, metaclass=cherrypy._AttributeDocstrings):
1847 """A CherryPy dict-like Session object (one per request)."""
1849 - __metaclass__ = cherrypy._AttributeDocstrings
1853 id_observers__doc = "A list of callbacks to which to pass new id's."
1855 self.id_observers = []
1858 - for k, v in kwargs.iteritems():
1859 + for k, v in kwargs.items():
1864 def has_key(self, key):
1865 """D.has_key(k) -> True if D has a key k, else False."""
1866 if not self.loaded: self.load()
1867 - return self._data.has_key(key)
1868 + return key in self._data
1870 def get(self, key, default=None):
1871 """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."""
1872 @@ -217,17 +215,17 @@
1874 """D.keys() -> list of D's keys."""
1875 if not self.loaded: self.load()
1876 - return self._data.keys()
1877 + return list(self._data.keys())
1880 """D.items() -> list of D's (key, value) pairs, as 2-tuples."""
1881 if not self.loaded: self.load()
1882 - return self._data.items()
1883 + return list(self._data.items())
1886 """D.values() -> list of D's values."""
1887 if not self.loaded: self.load()
1888 - return self._data.values()
1889 + return list(self._data.values())
1892 class RamSession(Session):
1895 """Clean up expired sessions."""
1896 now = datetime.datetime.now()
1897 - for id, (data, expiration_time) in self.cache.items():
1898 + for id, (data, expiration_time) in list(self.cache.items()):
1899 if expiration_time < now:
1903 # The 'storage_path' arg is required for file-based sessions.
1904 kwargs['storage_path'] = os.path.abspath(kwargs['storage_path'])
1906 - for k, v in kwargs.iteritems():
1907 + for k, v in kwargs.items():
1910 # Warn if any lock files exist at startup.
1912 This should only be called once per process; this will be done
1913 automatically when using sessions.init (as the built-in Tool does).
1915 - for k, v in kwargs.iteritems():
1916 + for k, v in kwargs.items():
1919 self.db = self.get_db()
1921 This should only be called once per process; this will be done
1922 automatically when using sessions.init (as the built-in Tool does).
1924 - for k, v in kwargs.iteritems():
1925 + for k, v in kwargs.items():
1929 diff -Naur client175_0.7-original/cherrypy/lib/static.py client175_0.7/cherrypy/lib/static.py
1930 --- client175_0.7-original/cherrypy/lib/static.py 2010-04-20 13:10:10.000000000 +0200
1931 +++ client175_0.7/cherrypy/lib/static.py 2021-08-03 14:46:56.870784689 +0200
1937 +import urllib.request, urllib.parse, urllib.error
1940 from cherrypy.lib import cptools, http, file_generator_limited
1942 boundary = mimetools.choose_boundary()
1943 ct = "multipart/byteranges; boundary=%s" % boundary
1944 response.headers['Content-Type'] = ct
1945 - if response.headers.has_key("Content-Length"):
1946 + if "Content-Length" in response.headers:
1947 # Delete Content-Length header so finalize() recalcs it.
1948 del response.headers["Content-Length"]
1952 section = section.rstrip(r"\/")
1953 branch = cherrypy.request.path_info[len(section) + 1:]
1954 - branch = urllib.unquote(branch.lstrip(r"\/"))
1955 + branch = urllib.parse.unquote(branch.lstrip(r"\/"))
1957 # If branch is "", filename will end in a slash
1958 filename = os.path.join(dir, branch)
1959 diff -Naur client175_0.7-original/cherrypy/lib/tidy.py client175_0.7/cherrypy/lib/tidy.py
1960 --- client175_0.7-original/cherrypy/lib/tidy.py 2010-04-20 13:10:10.000000000 +0200
1961 +++ client175_0.7/cherrypy/lib/tidy.py 2021-08-03 14:47:04.222669487 +0200
1974 response.body = wrong_content('<br />'.join(new_errs), orig_body)
1975 - if response.headers.has_key("Content-Length"):
1976 + if "Content-Length" in response.headers:
1977 # Delete Content-Length header so finalize() recalcs it.
1978 del response.headers["Content-Length"]
1981 enctag = '<?xml version="1.0" encoding="%s"?>' % encoding
1982 orig_body = enctag + orig_body
1984 - f = StringIO.StringIO(orig_body)
1985 + f = io.StringIO(orig_body)
1990 - body_file = StringIO.StringIO()
1991 + body_file = io.StringIO()
1992 traceback.print_exc(file = body_file)
1993 body_file = '<br />'.join(body_file.getvalue())
1994 response.body = wrong_content(body_file, orig_body, "XML")
1995 - if response.headers.has_key("Content-Length"):
1996 + if "Content-Length" in response.headers:
1997 # Delete Content-Length header so finalize() recalcs it.
1998 del response.headers["Content-Length"]
2002 response.body = [output]
2003 - if response.headers.has_key("Content-Length"):
2004 + if "Content-Length" in response.headers:
2005 # Delete Content-Length header so finalize() recalcs it.
2006 del response.headers["Content-Length"]
2011 response.body = wrong_content('<br />'.join(new_errs), orig_body)
2012 - if response.headers.has_key("Content-Length"):
2013 + if "Content-Length" in response.headers:
2014 # Delete Content-Length header so finalize() recalcs it.
2015 del response.headers["Content-Length"]
2017 diff -Naur client175_0.7-original/cherrypy/lib/wsgiapp.py client175_0.7/cherrypy/lib/wsgiapp.py
2018 --- client175_0.7-original/cherrypy/lib/wsgiapp.py 2010-04-20 13:10:10.000000000 +0200
2019 +++ client175_0.7/cherrypy/lib/wsgiapp.py 2021-08-03 14:47:15.738490577 +0200
2021 headers = request.headers
2022 environ["CONTENT_TYPE"] = headers.get("Content-type", "")
2023 environ["CONTENT_LENGTH"] = headers.get("Content-length", "")
2024 - for (k, v) in headers.iteritems():
2025 + for (k, v) in headers.items():
2026 envname = "HTTP_" + k.upper().replace("-","_")
2027 environ[envname] = v
2029 diff -Naur client175_0.7-original/cherrypy/lib/xmlrpc.py client175_0.7/cherrypy/lib/xmlrpc.py
2030 --- client175_0.7-original/cherrypy/lib/xmlrpc.py 2010-04-20 13:10:10.000000000 +0200
2031 +++ client175_0.7/cherrypy/lib/xmlrpc.py 2021-08-03 14:47:22.378387654 +0200
2034 """Return (params, method) from request body."""
2037 - return xmlrpclib.loads(cherrypy.request.body.read())
2038 + import xmlrpc.client
2039 + return xmlrpc.client.loads(cherrypy.request.body.read())
2041 return ('ERROR PARAMS', ), 'ERRORMETHOD'
2046 def respond(body, encoding='utf-8', allow_none=0):
2048 - if not isinstance(body, xmlrpclib.Fault):
2049 + import xmlrpc.client
2050 + if not isinstance(body, xmlrpc.client.Fault):
2052 - _set_response(xmlrpclib.dumps(body, methodresponse=1,
2053 + _set_response(xmlrpc.client.dumps(body, methodresponse=1,
2055 allow_none=allow_none))
2057 def on_error(*args, **kwargs):
2058 body = str(sys.exc_info()[1])
2060 - _set_response(xmlrpclib.dumps(xmlrpclib.Fault(1, body)))
2061 + import xmlrpc.client
2062 + _set_response(xmlrpc.client.dumps(xmlrpc.client.Fault(1, body)))
2064 diff -Naur client175_0.7-original/cherrypy/process/plugins.py client175_0.7/cherrypy/process/plugins.py
2065 --- client175_0.7-original/cherrypy/process/plugins.py 2010-04-20 13:10:10.000000000 +0200
2066 +++ client175_0.7/cherrypy/process/plugins.py 2021-08-03 14:48:07.409700439 +0200
2069 # Map from signal numbers to names
2071 - for k, v in vars(_signal).items():
2072 + for k, v in list(vars(_signal).items()):
2073 if k.startswith('SIG') and not k.startswith('SIG_'):
2077 self._previous_handlers = {}
2079 def subscribe(self):
2080 - for sig, func in self.handlers.iteritems():
2081 + for sig, func in self.handlers.items():
2083 self.set_handler(sig, func)
2087 def unsubscribe(self):
2088 - for signum, handler in self._previous_handlers.iteritems():
2089 + for signum, handler in self._previous_handlers.items():
2090 signame = self.signals[signum]
2094 If the given signal name or number is not available on the current
2095 platform, ValueError is raised.
2097 - if isinstance(signal, basestring):
2098 + if isinstance(signal, str):
2099 signum = getattr(_signal, signal, None)
2101 raise ValueError("No such signal: %r" % signal)
2103 self.bus.log("pwd module not available; ignoring uid.",
2106 - elif isinstance(val, basestring):
2107 + elif isinstance(val, str):
2108 val = pwd.getpwnam(val)[2]
2110 uid = property(_get_uid, _set_uid, doc="The uid under which to run.")
2112 self.bus.log("grp module not available; ignoring gid.",
2115 - elif isinstance(val, basestring):
2116 + elif isinstance(val, str):
2117 val = grp.getgrnam(val)[2]
2119 gid = property(_get_gid, _set_gid, doc="The gid under which to run.")
2121 # This is the first parent. Exit, now that we've forked.
2122 self.bus.log('Forking once.')
2124 - except OSError, exc:
2125 + except OSError as exc:
2126 # Python raises OSError rather than returning negative numbers.
2127 sys.exit("%s: fork #1 failed: (%d) %s\n"
2128 % (sys.argv[0], exc.errno, exc.strerror))
2131 self.bus.log('Forking twice.')
2132 os._exit(0) # Exit second parent
2133 - except OSError, exc:
2134 + except OSError as exc:
2135 sys.exit("%s: fork #2 failed: (%d) %s\n"
2136 % (sys.argv[0], exc.errno, exc.strerror))
2140 """Reload the process if registered files have been modified."""
2142 - for k, m in sys.modules.items():
2143 + for k, m in list(sys.modules.items()):
2144 if re.match(self.match, k):
2145 if hasattr(m, '__loader__'):
2146 if hasattr(m.__loader__, 'archive'):
2150 """Release all threads and run all 'stop_thread' listeners."""
2151 - for thread_ident, i in self.threads.iteritems():
2152 + for thread_ident, i in self.threads.items():
2153 self.bus.publish('stop_thread', i)
2154 self.threads.clear()
2156 diff -Naur client175_0.7-original/cherrypy/process/servers.py client175_0.7/cherrypy/process/servers.py
2157 --- client175_0.7-original/cherrypy/process/servers.py 2010-04-20 13:10:10.000000000 +0200
2158 +++ client175_0.7/cherrypy/process/servers.py 2021-08-03 14:48:16.165568167 +0200
2162 self.httpserver.start()
2163 - except KeyboardInterrupt, exc:
2164 + except KeyboardInterrupt as exc:
2165 self.bus.log("<Ctrl-C> hit: shutting down HTTP server")
2166 self.interrupt = exc
2168 - except SystemExit, exc:
2169 + except SystemExit as exc:
2170 self.bus.log("SystemExit raised: shutting down HTTP server")
2171 self.interrupt = exc
2175 raise ValueError("Host values of '' or None are not allowed.")
2177 - for trial in xrange(50):
2178 + for trial in range(50):
2180 # we are expecting a free port, so reduce the timeout
2181 check_port(host, port, timeout=0.1)
2184 raise ValueError("Host values of '' or None are not allowed.")
2186 - for trial in xrange(50):
2187 + for trial in range(50):
2189 check_port(host, port)
2191 diff -Naur client175_0.7-original/cherrypy/process/win32.py client175_0.7/cherrypy/process/win32.py
2192 --- client175_0.7-original/cherrypy/process/win32.py 2010-04-20 13:10:10.000000000 +0200
2193 +++ client175_0.7/cherrypy/process/win32.py 2021-08-03 14:48:22.801468164 +0200
2195 """Windows service. Requires pywin32."""
2204 return self.events[state]
2206 event = win32event.CreateEvent(None, 0, 0,
2207 - u"WSPBus %s Event (pid=%r)" %
2208 + "WSPBus %s Event (pid=%r)" %
2209 (state.name, os.getpid()))
2210 self.events[state] = event
2214 def key_for(self, obj):
2215 """For the given value, return its corresponding key."""
2216 - for key, val in self.iteritems():
2217 + for key, val in self.items():
2220 raise ValueError("The given object could not be found: %r" % obj)
2221 diff -Naur client175_0.7-original/cherrypy/process/wspbus.py client175_0.7/cherrypy/process/wspbus.py
2222 --- client175_0.7-original/cherrypy/process/wspbus.py 2010-04-20 13:10:10.000000000 +0200
2223 +++ client175_0.7/cherrypy/process/wspbus.py 2021-08-03 14:48:29.181372091 +0200
2225 output.append(listener(*args, **kwargs))
2226 except KeyboardInterrupt:
2228 - except SystemExit, e:
2229 + except SystemExit as e:
2230 # If we have previous errors ensure the exit code is non-zero
2231 if exc and e.code == 0:
2235 # Any stop/exit errors will be logged inside publish().
2237 - raise e_info[0], e_info[1], e_info[2]
2238 + raise e_info[0](e_info[1]).with_traceback(e_info[2])
2241 """Stop all services and prepare to exit the process."""
2242 diff -Naur client175_0.7-original/cherrypy/wsgiserver/__init__.py client175_0.7/cherrypy/wsgiserver/__init__.py
2243 --- client175_0.7-original/cherrypy/wsgiserver/__init__.py 2010-04-20 13:10:10.000000000 +0200
2244 +++ client175_0.7/cherrypy/wsgiserver/__init__.py 2021-08-03 14:49:05.556826062 +0200
2252 quoted_slash = re.compile("(?i)%2F")
2256 - import cStringIO as StringIO
2257 + import io as StringIO
2262 -_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
2263 +_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, str)
2269 -from urllib import unquote
2270 -from urlparse import urlparse
2271 +from urllib.parse import unquote
2272 +from urllib.parse import urlparse
2277 errno_names = dir(errno)
2278 nums = [getattr(errno, k) for k in errnames if k in errno_names]
2280 - return dict.fromkeys(nums).keys()
2281 + return list(dict.fromkeys(nums).keys())
2283 socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
2287 def __init__(self, apps):
2289 - apps = apps.items()
2290 + apps = list(apps.items())
2291 except AttributeError:
2299 - data = self.rfile.next()
2300 + def __next__(self):
2301 + data = next(self.rfile)
2302 self.bytes_read += len(data)
2303 self._check_length()
2306 # then all the http headers
2309 - except ValueError, ex:
2310 + except ValueError as ex:
2311 self.simple_response("400 Bad Request", repr(ex.args))
2315 def decode_chunked(self):
2316 """Decode the 'chunked' transfer coding."""
2318 - data = StringIO.StringIO()
2319 + data = io.StringIO()
2321 line = self.rfile.readline().strip().split(";", 1)
2322 chunk_size = int(line.pop(0), 16)
2326 self.wfile.sendall("".join(buf))
2327 - except socket.error, x:
2328 + except socket.error as x:
2329 if x.args[0] not in socket_errors_to_ignore:
2334 if self.sent_headers:
2336 - raise exc_info[0], exc_info[1], exc_info[2]
2337 + raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
2343 bytes_sent = self.send(data)
2344 data = data[bytes_sent:]
2345 - except socket.error, e:
2346 + except socket.error as e:
2347 if e.args[0] not in socket_errors_nonblocking:
2353 return self._sock.recv(size)
2354 - except socket.error, e:
2355 + except socket.error as e:
2356 if (e.args[0] not in socket_errors_nonblocking
2357 and e.args[0] not in socket_error_eintr):
2360 buf.seek(0, 2) # seek end
2363 - self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
2364 + self._rbuf = io.StringIO() # reset _rbuf. we consume it via buf.
2366 data = self.recv(rbufsize)
2368 @@ -776,11 +776,11 @@
2369 # Already have size bytes in our buffer? Extract and return.
2372 - self._rbuf = StringIO.StringIO()
2373 + self._rbuf = io.StringIO()
2374 self._rbuf.write(buf.read())
2377 - self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
2378 + self._rbuf = io.StringIO() # reset _rbuf. we consume it via buf.
2380 left = size - buf_len
2381 # recv() will malloc the amount of memory given as its
2384 bline = buf.readline(size)
2385 if bline.endswith('\n') or len(bline) == size:
2386 - self._rbuf = StringIO.StringIO()
2387 + self._rbuf = io.StringIO()
2388 self._rbuf.write(buf.read())
2392 # Speed up unbuffered case
2394 buffers = [buf.read()]
2395 - self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
2396 + self._rbuf = io.StringIO() # reset _rbuf. we consume it via buf.
2401 return "".join(buffers)
2403 buf.seek(0, 2) # seek end
2404 - self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
2405 + self._rbuf = io.StringIO() # reset _rbuf. we consume it via buf.
2407 data = self.recv(self._rbufsize)
2409 @@ -860,10 +860,10 @@
2413 - self._rbuf = StringIO.StringIO()
2414 + self._rbuf = io.StringIO()
2415 self._rbuf.write(buf.read())
2417 - self._rbuf = StringIO.StringIO() # reset _rbuf. we consume it via buf.
2418 + self._rbuf = io.StringIO() # reset _rbuf. we consume it via buf.
2420 data = self.recv(self._rbufsize)
2424 bytes_sent = self.send(data)
2425 data = data[bytes_sent:]
2426 - except socket.error, e:
2427 + except socket.error as e:
2428 if e.args[0] not in socket_errors_nonblocking:
2434 return self._sock.recv(size)
2435 - except socket.error, e:
2436 + except socket.error as e:
2437 if (e.args[0] not in socket_errors_nonblocking
2438 and e.args[0] not in socket_error_eintr):
2440 @@ -1065,7 +1065,7 @@
2441 time.sleep(self.ssl_retry)
2442 except SSL.WantWriteError:
2443 time.sleep(self.ssl_retry)
2444 - except SSL.SysCallError, e:
2445 + except SSL.SysCallError as e:
2446 if is_reader and e.args == (-1, 'Unexpected EOF'):
2449 @@ -1073,7 +1073,7 @@
2450 if is_reader and errnum in socket_errors_to_ignore:
2452 raise socket.error(errnum)
2453 - except SSL.Error, e:
2454 + except SSL.Error as e:
2455 if is_reader and e.args == (-1, 'Unexpected EOF'):
2458 @@ -1175,7 +1175,7 @@
2459 if req.close_connection:
2462 - except socket.error, e:
2463 + except socket.error as e:
2465 if errnum == 'timed out':
2466 if req and not req.sent_headers:
2467 @@ -1187,7 +1187,7 @@
2469 except (KeyboardInterrupt, SystemExit):
2471 - except FatalSSLAlert, e:
2472 + except FatalSSLAlert as e:
2473 # Close the connection.
2476 @@ -1198,7 +1198,7 @@
2477 "The client sent a plain HTTP request, but "
2478 "this server only speaks HTTPS on this port.")
2480 - except Exception, e:
2481 + except Exception as e:
2482 if req and not req.sent_headers:
2483 req.simple_response("500 Internal Server Error", format_exc())
2485 @@ -1272,7 +1272,7 @@
2489 - except (KeyboardInterrupt, SystemExit), exc:
2490 + except (KeyboardInterrupt, SystemExit) as exc:
2491 self.server.interrupt = exc
2494 @@ -1288,12 +1288,12 @@
2498 - self._queue = Queue.Queue()
2499 + self._queue = queue.Queue()
2500 self.get = self._queue.get
2503 """Start the pool of threads."""
2504 - for i in xrange(self.min):
2505 + for i in range(self.min):
2506 self._threads.append(WorkerThread(self.server))
2507 for worker in self._threads:
2508 worker.setName("CP WSGIServer " + worker.getName())
2509 @@ -1314,7 +1314,7 @@
2511 def grow(self, amount):
2512 """Spawn new worker threads (not above self.max)."""
2513 - for i in xrange(amount):
2514 + for i in range(amount):
2515 if self.max > 0 and len(self._threads) >= self.max:
2517 worker = WorkerThread(self.server)
2518 @@ -1332,7 +1332,7 @@
2522 - for i in xrange(min(amount, len(self._threads) - self.min)):
2523 + for i in range(min(amount, len(self._threads) - self.min)):
2524 # Put a number of shutdown requests on the queue equal
2525 # to 'amount'. Once each of those is processed by a worker,
2526 # that worker will terminate and be culled from our list
2527 @@ -1369,7 +1369,7 @@
2528 except (AssertionError,
2529 # Ignore repeated Ctrl-C.
2530 # See http://www.cherrypy.org/ticket/691.
2531 - KeyboardInterrupt), exc1:
2532 + KeyboardInterrupt) as exc1:
2536 @@ -1392,13 +1392,13 @@
2537 'sock_shutdown', 'get_peer_certificate', 'want_read',
2538 'want_write', 'set_connect_state', 'set_accept_state',
2539 'connect_ex', 'sendall', 'settimeout'):
2540 - exec """def %s(self, *args):
2541 + exec("""def %s(self, *args):
2542 self._lock.acquire()
2544 return self._ssl_conn.%s(*args)
2546 self._lock.release()
2552 @@ -1557,7 +1557,7 @@
2553 self._interrupt = None
2555 # Select the appropriate socket
2556 - if isinstance(self.bind_addr, basestring):
2557 + if isinstance(self.bind_addr, str):
2560 # So we can reuse the socket...
2561 @@ -1565,7 +1565,7 @@
2564 # So everyone can access the socket...
2565 - try: os.chmod(self.bind_addr, 0777)
2566 + try: os.chmod(self.bind_addr, 0o777)
2569 info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
2570 @@ -1586,14 +1586,14 @@
2571 af, socktype, proto, canonname, sa = res
2573 self.bind(af, socktype, proto)
2574 - except socket.error, msg:
2575 + except socket.error as msg:
2582 - raise socket.error, msg
2583 + raise socket.error(msg)
2585 # Timeout so KeyboardInterrupt can be caught on Win32
2586 self.socket.settimeout(1)
2587 @@ -1632,7 +1632,7 @@
2589 # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
2590 # activate dual-stack. See http://www.cherrypy.org/ticket/871.
2591 - if (not isinstance(self.bind_addr, basestring)
2592 + if (not isinstance(self.bind_addr, str)
2593 and self.bind_addr[0] == '::' and family == socket.AF_INET6):
2595 self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
2596 @@ -1664,7 +1664,7 @@
2597 environ["ACTUAL_SERVER_PROTOCOL"] = self.protocol
2598 environ["SERVER_NAME"] = self.server_name
2600 - if isinstance(self.bind_addr, basestring):
2601 + if isinstance(self.bind_addr, str):
2602 # AF_UNIX. This isn't really allowed by WSGI, which doesn't
2603 # address unix domain sockets. But it's better than nothing.
2604 environ["SERVER_PORT"] = ""
2605 @@ -1682,7 +1682,7 @@
2606 # notice keyboard interrupts on Win32, which don't interrupt
2607 # accept() by default
2609 - except socket.error, x:
2610 + except socket.error as x:
2611 if x.args[0] in socket_error_eintr:
2612 # I *think* this is right. EINTR should occur when a signal
2613 # is received during the accept() call; all docs say retry
2614 @@ -1715,11 +1715,11 @@
2616 sock = getattr(self, "socket", None)
2618 - if not isinstance(self.bind_addr, basestring):
2619 + if not isinstance(self.bind_addr, str):
2620 # Touch our own socket to make accept() return immediately.
2622 host, port = sock.getsockname()[:2]
2623 - except socket.error, x:
2624 + except socket.error as x:
2625 if x.args[0] not in socket_errors_to_ignore:
2628 diff -Naur client175_0.7-original/covers.py client175_0.7/covers.py
2629 --- client175_0.7-original/covers.py 2011-04-02 03:51:24.000000000 +0200
2630 +++ client175_0.7/covers.py 2021-08-03 14:39:46.713265947 +0200
2632 # Exaile (http://www.exaile.org/).
2635 -import hashlib, re, urllib, os, time, shutil, threading
2636 +import hashlib, re, urllib.request, urllib.parse, urllib.error, os, time, shutil, threading
2637 from xml.etree import ElementTree as ET
2638 from datetime import datetime, timedelta
2642 def _findMusicBrainz(self, vars):
2643 self._delay('last_MB_lookup')
2644 - data = urllib.urlopen(self.urlMB % vars).read()
2645 + data = urllib.request.urlopen(self.urlMB % vars).read()
2646 m = self.regexMB.search(data)
2650 url = "http://images.amazon.com/images/P/%s.01.%sZZZZZZZ.jpg"
2651 for sz in ['L', 'M']:
2652 image = url % (asin, sz)
2653 - h = urllib.urlopen(image)
2654 + h = urllib.request.urlopen(image)
2657 if len(data) > 1000:
2660 def _findLastFM_album(self, vars):
2661 self._delay('last_FM_lookup')
2662 - data = urllib.urlopen(self.urlFM % vars).read()
2663 + data = urllib.request.urlopen(self.urlFM % vars).read()
2666 - print 'LASTFM SEARCH: ERROR PARSING LASTFM DATA!'
2667 + print('LASTFM SEARCH: ERROR PARSING LASTFM DATA!')
2670 c = x.find('coverart')
2672 - print 'LASTFM SEARCH: NO COVERART NODE IN LASTFM DATA!'
2673 + print('LASTFM SEARCH: NO COVERART NODE IN LASTFM DATA!')
2676 for sz in ['large', 'medium', 'small']:
2677 image = c.findtext(sz, '')
2678 if image > '' and not image.lower().endswith('.gif'):
2679 - h = urllib.urlopen(image)
2680 + h = urllib.request.urlopen(image)
2683 if hashlib.sha1(data).hexdigest() != "57b2c37343f711c94e83a37bd91bc4d18d2ed9d5":
2684 @@ -120,13 +120,13 @@
2686 def _findLastFM_artist(self, vars):
2687 self._delay('last_FM_lookup')
2688 - data = urllib.urlopen(self.urlFM_artist % vars['artist']).read()
2689 + data = urllib.request.urlopen(self.urlFM_artist % vars['artist']).read()
2690 m = self.regexFM_artist.search(data)
2693 if image.lower().endswith('.gif'):
2695 - h = urllib.urlopen(image)
2696 + h = urllib.request.urlopen(image)
2699 if hashlib.sha1(data).hexdigest() != "57b2c37343f711c94e83a37bd91bc4d18d2ed9d5":
2702 shutil.copy2(coverpath, cover_destination)
2704 - print "Could not save cover to: " + cover_destination
2705 - print "For best performance, please ensure that the directory exists and is writable."
2706 + print("Could not save cover to: " + cover_destination)
2707 + print("For best performance, please ensure that the directory exists and is writable.")
2708 h = open(coverpath, 'r')
2712 return covername, None
2715 - 'album': urllib.quote_plus(album.encode("utf-8")),
2716 - 'artist': urllib.quote_plus(artist.encode("utf-8"))
2717 + 'album': urllib.parse.quote_plus(album.encode("utf-8")),
2718 + 'artist': urllib.parse.quote_plus(artist.encode("utf-8"))
2726 - print "Could not save cover to: " + coverpath
2727 - print "For best performance, please ensure that the directory exists and is writable."
2728 + print("Could not save cover to: " + coverpath)
2729 + print("For best performance, please ensure that the directory exists and is writable.")
2731 return covername, data
2733 diff -Naur client175_0.7-original/lyricwiki.py client175_0.7/lyricwiki.py
2734 --- client175_0.7-original/lyricwiki.py 2010-11-20 18:43:24.000000000 +0100
2735 +++ client175_0.7/lyricwiki.py 2021-08-03 14:40:00.301064572 +0200
2737 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
2738 # MA 02110-1301, USA.
2740 -import json, urllib, os, hashlib, time
2741 +import json, urllib.request, urllib.parse, urllib.error, os, hashlib, time
2743 def _download(args):
2747 str_args[key] = args[key].encode("utf-8")
2749 - args = urllib.urlencode(str_args)
2750 + args = urllib.parse.urlencode(str_args)
2752 - return urllib.urlopen(base + args).read()
2753 + return urllib.request.urlopen(base + args).read()
2755 def _get_page_titles(artist, title):
2757 diff -Naur client175_0.7-original/metadata/_base.py client175_0.7/metadata/_base.py
2758 --- client175_0.7-original/metadata/_base.py 2010-05-01 21:15:15.000000000 +0200
2759 +++ client175_0.7/metadata/_base.py 2021-08-03 14:51:24.062763658 +0200
2763 self._reverse_mapping = dict((
2764 - (v,k) for k,v in self.tag_mapping.iteritems() ))
2765 + (v,k) for k,v in self.tag_mapping.items() ))
2771 def _get_keys(self):
2773 - for k in self._get_raw().keys():
2774 + for k in list(self._get_raw().keys()):
2775 if k in self._reverse_mapping:
2776 keys.append(self._reverse_mapping[k])
2778 @@ -149,11 +149,11 @@
2779 if t == None and tag in self.tag_mapping:
2781 t = self._get_tag(raw, self.tag_mapping[tag])
2782 - if type(t) in [str, unicode]:
2783 + if type(t) in [str, str]:
2787 - t = [unicode(u) for u in list(t)]
2788 + t = [str(u) for u in list(t)]
2789 except UnicodeDecodeError:
2791 except (KeyError, TypeError):
2792 @@ -161,10 +161,10 @@
2793 if t == None and self.others:
2795 t = self._get_tag(raw, tag)
2796 - if type(t) in [str, unicode]:
2797 + if type(t) in [str, str]:
2800 - t = [unicode(u) for u in list(t)]
2801 + t = [str(u) for u in list(t)]
2802 except (KeyError, TypeError):
2808 # tags starting with __ are internal and should not be written
2809 - for tag in tagdict.keys():
2810 + for tag in list(tagdict.keys()):
2811 if tag.startswith("__"):
2814 diff -Naur client175_0.7-original/metadata/_id3.py client175_0.7/metadata/_id3.py
2815 --- client175_0.7-original/metadata/_id3.py 2010-05-04 23:50:41.000000000 +0200
2816 +++ client175_0.7/metadata/_id3.py 2021-08-03 14:51:42.866483930 +0200
2819 def _get_tag(self, raw, t):
2820 if not raw.tags: return []
2821 - if t not in self.tag_mapping.itervalues():
2822 + if t not in iter(self.tag_mapping.values()):
2824 field = raw.tags.getall(t)
2828 if t == 'TDRC' or t == 'TDOR': # values are ID3TimeStamps
2830 - ret.extend([unicode(x) for x in value.text])
2831 + ret.extend([str(x) for x in value.text])
2832 elif t == 'USLT': # Lyrics are stored in plain old strings
2834 - ret.append(unicode(value.text))
2835 + ret.append(str(value.text))
2836 elif t == 'WOAR': # URLS are stored in url not text
2838 - ret.extend([unicode(x.replace('\n','').replace('\r','')) \
2839 + ret.extend([str(x.replace('\n','').replace('\r','')) \
2840 for x in value.url])
2842 ret = [x.data for x in field]
2846 - ret.extend([unicode(x.replace('\n','').replace('\r','')) \
2847 + ret.extend([str(x.replace('\n','').replace('\r','')) \
2848 for x in value.text])
2853 def _set_tag(self, raw, tag, data):
2854 - if tag not in self.tag_mapping.itervalues():
2855 + if tag not in iter(self.tag_mapping.values()):
2857 if raw.tags is not None:
2858 raw.tags.delall(tag)
2862 def _del_tag(self, raw, tag):
2863 - if tag not in self.tag_mapping.itervalues():
2864 + if tag not in iter(self.tag_mapping.values()):
2866 if raw.tags is not None:
2867 raw.tags.delall(tag)
2868 diff -Naur client175_0.7-original/metadata/__init__.py client175_0.7/metadata/__init__.py
2869 --- client175_0.7-original/metadata/__init__.py 2010-05-01 21:15:15.000000000 +0200
2870 +++ client175_0.7/metadata/__init__.py 2021-08-03 14:50:50.391263894 +0200
2874 from metadata._base import BaseFormat, NotWritable, NotReadable
2876 +import urllib.parse
2878 from metadata import (ape, asf, flac, mod, mp3, mp4, mpc, ogg, sid, speex,
2880 diff -Naur client175_0.7-original/metadata/mp4.py client175_0.7/metadata/mp4.py
2881 --- client175_0.7-original/metadata/mp4.py 2010-05-01 21:15:15.000000000 +0200
2882 +++ client175_0.7/metadata/mp4.py 2021-08-03 14:52:08.706100110 +0200
2886 def _get_tag(self, f, name):
2887 - if not f.has_key(name):
2890 elif name in ['trkn', 'disk']:
2896 - tmp = map(int, val.split('/'))
2897 + tmp = list(map(int, val.split('/')))
2898 f[name].append(tuple(tmp))
2901 diff -Naur client175_0.7-original/mpd.py client175_0.7/mpd.py
2902 --- client175_0.7-original/mpd.py 2010-08-27 00:38:39.000000000 +0200
2903 +++ client175_0.7/mpd.py 2021-08-03 14:40:15.808834774 +0200
2907 def extend_database(item):
2908 - keys = item.keys()
2909 + keys = list(item.keys())
2911 item = extend_file(item)
2912 elif 'directory' in keys:
2916 return self._execute(command, args, retval)
2917 - except (ConnectionError, socket.error), e:
2918 - print "%s\n reconnecting..." % e
2919 + except (ConnectionError, socket.error) as e:
2920 + print("%s\n reconnecting..." % e)
2924 @@ -343,13 +343,13 @@
2927 def _fetch_songs(self):
2928 - return map(extend_file, self._read_songs())
2929 + return list(map(extend_file, self._read_songs()))
2931 def _fetch_playlists(self):
2932 return self._fetch_objects(["playlist"])
2934 def _fetch_database(self):
2935 - return map(extend_database, self._read_objects(["file", "directory", "playlist"]))
2936 + return list(map(extend_database, self._read_objects(["file", "directory", "playlist"])))
2938 def _fetch_outputs(self):
2939 return self._fetch_objects(["outputid"])
2942 sock = socket.socket(af, socktype, proto)
2944 - except socket.error, msg:
2945 + except socket.error as msg:
2950 self.password(_password)
2951 self._TAGS = self.tagtypes()
2952 self._TAGS.extend(['Pos', 'Time', 'Id'])
2953 - self._TAGS_LOWER = map(str.lower, self._TAGS)
2954 - self._TAGMAP = dict(zip(self._TAGS, self._TAGS_LOWER))
2955 + self._TAGS_LOWER = list(map(str.lower, self._TAGS))
2956 + self._TAGMAP = dict(list(zip(self._TAGS, self._TAGS_LOWER)))
2960 diff -Naur client175_0.7-original/mutagen/apev2.py client175_0.7/mutagen/apev2.py
2961 --- client175_0.7-original/mutagen/apev2.py 2010-05-15 00:42:14.000000000 +0200
2962 +++ client175_0.7/mutagen/apev2.py 2021-08-03 14:53:33.292843836 +0200
2964 __all__ = ["APEv2", "APEv2File", "Open", "delete"]
2967 -from cStringIO import StringIO
2968 +from io import StringIO
2970 def is_valid_apev2_key(key):
2971 return (2 <= len(key) <= 255 and min(key) >= ' ' and max(key) <= '~' and
2973 # 1: Item contains binary information
2974 # 2: Item is a locator of external stored information [e.g. URL]
2976 -TEXT, BINARY, EXTERNAL = range(3)
2977 +TEXT, BINARY, EXTERNAL = list(range(3))
2979 -HAS_HEADER = 1L << 31
2980 -HAS_NO_FOOTER = 1L << 30
2981 -IS_HEADER = 1L << 29
2982 +HAS_HEADER = 1 << 31
2983 +HAS_NO_FOOTER = 1 << 30
2984 +IS_HEADER = 1 << 29
2986 class error(IOError): pass
2987 class APENoHeaderError(error, ValueError): pass
2991 """Return tag key=value pairs in a human-readable format."""
2992 - items = self.items()
2993 + items = list(self.items())
2995 return "\n".join(["%s=%s" % (k, v.pprint()) for k, v in items])
2999 if not isinstance(value, _APEValue):
3000 # let's guess at the content if we're not already a value...
3001 - if isinstance(value, unicode):
3002 + if isinstance(value, str):
3003 # unicode? we've got to be text.
3004 value = APEValue(utf8(value), TEXT)
3005 elif isinstance(value, list):
3007 self.__dict[key.lower()] = value
3010 - return [self.__casemap.get(key, key) for key in self.__dict.keys()]
3011 + return [self.__casemap.get(key, key) for key in list(self.__dict.keys())]
3013 def save(self, filename=None):
3014 """Save changes to a file.
3016 # "APE tags items should be sorted ascending by size... This is
3017 # not a MUST, but STRONGLY recommended. Actually the items should
3018 # be sorted by importance/byte, but this is not feasible."
3019 - tags = [v._internal(k) for k, v in self.items()]
3020 + tags = [v._internal(k) for k, v in list(self.items())]
3021 tags.sort(lambda a, b: cmp(len(a), len(b)))
3022 num_tags = len(tags)
3023 tags = "".join(tags)
3024 @@ -401,20 +401,20 @@
3025 strings (with a null seperating the values), or arrays of strings."""
3027 def __unicode__(self):
3028 - return unicode(str(self), "utf-8")
3029 + return str(str(self), "utf-8")
3032 """Iterate over the strings of the value (not the characters)"""
3033 - return iter(unicode(self).split("\0"))
3034 + return iter(str(self).split("\0"))
3036 def __getitem__(self, index):
3037 - return unicode(self).split("\0")[index]
3038 + return str(self).split("\0")[index]
3041 return self.value.count("\0") + 1
3043 def __cmp__(self, other):
3044 - return cmp(unicode(self), other)
3045 + return cmp(str(self), other)
3047 def __setitem__(self, index, value):
3051 External values are usually URI or IRI strings.
3053 - def pprint(self): return "[External] %s" % unicode(self)
3054 + def pprint(self): return "[External] %s" % str(self)
3056 class APEv2File(FileType):
3057 class _Info(object):
3058 diff -Naur client175_0.7-original/mutagen/asf.py client175_0.7/mutagen/asf.py
3059 --- client175_0.7-original/mutagen/asf.py 2010-05-15 00:42:14.000000000 +0200
3060 +++ client175_0.7/mutagen/asf.py 2021-08-03 14:53:40.512736644 +0200
3064 values = [value for (k, value) in self if k == key]
3065 - if not values: raise KeyError, key
3066 + if not values: raise KeyError(key)
3069 def __delitem__(self, key):
3070 """Delete all values associated with the key."""
3071 - to_delete = filter(lambda x: x[0] == key, self)
3072 - if not to_delete: raise KeyError, key
3073 - else: map(self.remove, to_delete)
3074 + to_delete = [x for x in self if x[0] == key]
3075 + if not to_delete: raise KeyError(key)
3076 + else: list(map(self.remove, to_delete))
3078 def __contains__(self, key):
3079 """Return true if the key has any values."""
3081 except KeyError: pass
3082 for value in values:
3083 if key in _standard_attribute_names:
3084 - value = unicode(value)
3085 + value = str(value)
3086 elif not isinstance(value, ASFBaseAttribute):
3087 - if isinstance(value, basestring):
3088 + if isinstance(value, str):
3089 value = ASFUnicodeAttribute(value)
3090 elif isinstance(value, bool):
3091 value = ASFBoolAttribute(value)
3092 elif isinstance(value, int):
3093 value = ASFDWordAttribute(value)
3094 - elif isinstance(value, long):
3095 + elif isinstance(value, int):
3096 value = ASFQWordAttribute(value)
3097 self.append((key, value))
3102 def __cmp__(self, other):
3103 - return cmp(unicode(self), other)
3104 + return cmp(str(self), other)
3107 class ASFByteArrayAttribute(ASFBaseAttribute):
3109 GUID = ASFGUIDAttribute.TYPE
3111 def ASFValue(value, kind, **kwargs):
3112 - for t, c in _attribute_types.items():
3113 + for t, c in list(_attribute_types.items()):
3115 return c(value=value, **kwargs)
3116 raise ValueError("Unknown value type")
3117 @@ -362,12 +362,12 @@
3120 title, author, copyright, desc, rating = texts
3121 - for key, value in dict(
3122 + for key, value in list(dict(
3125 Copyright=copyright,
3127 - Rating=rating).items():
3128 + Rating=rating).items()):
3129 if value is not None:
3130 asf.tags[key] = value
3133 return value[0].encode("utf-16-le") + "\x00\x00"
3136 - texts = map(render_text, _standard_attribute_names)
3137 - data = struct.pack("<HHHHH", *map(len, texts)) + "".join(texts)
3138 + texts = list(map(render_text, _standard_attribute_names))
3139 + data = struct.pack("<HHHHH", *list(map(len, texts))) + "".join(texts)
3140 return self.GUID + struct.pack("<Q", 24 + len(data)) + data
3144 asf.tags.append((name, attr))
3146 def render(self, asf):
3147 - attrs = asf.to_extended_content_description.items()
3148 + attrs = list(asf.to_extended_content_description.items())
3149 data = "".join([attr.render(name) for (name, attr) in attrs])
3150 data = struct.pack("<QH", 26 + len(data), len(attrs)) + data
3151 return self.GUID + data
3153 asf.tags.append((name, attr))
3155 def render(self, asf):
3156 - attrs = asf.to_metadata.items()
3157 + attrs = list(asf.to_metadata.items())
3158 data = "".join([attr.render_m(name) for (name, attr) in attrs])
3159 return (self.GUID + struct.pack("<QH", 26 + len(data), len(attrs)) +
3162 def __read_file(self, fileobj):
3163 header = fileobj.read(30)
3164 if len(header) != 30 or header[:16] != HeaderObject.GUID:
3165 - raise ASFHeaderError, "Not an ASF file."
3166 + raise ASFHeaderError("Not an ASF file.")
3168 self.extended_content_description_obj = None
3169 self.content_description_obj = None
3170 diff -Naur client175_0.7-original/mutagen/_constants.py client175_0.7/mutagen/_constants.py
3171 --- client175_0.7-original/mutagen/_constants.py 2010-05-15 00:42:14.000000000 +0200
3172 +++ client175_0.7/mutagen/_constants.py 2021-08-03 14:54:27.292044501 +0200
3174 """Constants used by Mutagen."""
3223 - u"Instrumental Pop",
3224 - u"Instrumental Rock",
3228 - u"Techno-Industrial",
3241 - u"Native American",
3269 - u"Progressive Rock",
3270 - u"Psychadelic Rock",
3271 - u"Symphonic Rock",
3275 - u"Easy Listening",
3313 - u"Christian Gangsta Rap",
3317 - u"Contemporary Christian",
3318 - u"Christian Rock",
3371 + "Instrumental Pop",
3372 + "Instrumental Rock",
3376 + "Techno-Industrial",
3389 + "Native American",
3417 + "Progressive Rock",
3418 + "Psychadelic Rock",
3461 + "Christian Gangsta Rap",
3465 + "Contemporary Christian",
3474 """The ID3v1 genre list."""
3475 diff -Naur client175_0.7-original/mutagen/easyid3.py client175_0.7/mutagen/easyid3.py
3476 --- client175_0.7-original/mutagen/easyid3.py 2010-05-15 00:42:14.000000000 +0200
3477 +++ client175_0.7/mutagen/easyid3.py 2021-08-03 14:54:43.607811287 +0200
3480 # Store 8859-1 if we can, per MusicBrainz spec.
3482 - if max(v) > u'\x7f':
3483 + if max(v) > '\x7f':
3485 id3.add(mutagen.id3.TXXX(encoding=enc, text=value, desc=desc))
3489 def __setitem__(self, key, value):
3491 - if isinstance(value, basestring):
3492 + if isinstance(value, str):
3494 func = dict_match(self.Set, key, self.SetFallback)
3495 if func is not None:
3500 - for key in self.Get.keys():
3501 + for key in list(self.Get.keys()):
3502 if key in self.List:
3503 keys.extend(self.List[key](self.__id3, key))
3507 raise EasyID3KeyError(key)
3509 - return [u"%+f dB" % frame.gain]
3510 + return ["%+f dB" % frame.gain]
3512 def gain_set(id3, key, value):
3516 raise EasyID3KeyError(key)
3518 - return [u"%f" % frame.peak]
3519 + return ["%f" % frame.peak]
3521 def peak_set(id3, key, value):
3524 "TSOT": "titlesort",
3526 "TSST": "discsubtitle",
3529 EasyID3.RegisterTextKey(key, frameid)
3531 EasyID3.RegisterKey("genre", genre_get, genre_set, genre_delete)
3532 @@ -444,20 +444,20 @@
3533 # http://bugs.musicbrainz.org/ticket/1383
3534 # http://musicbrainz.org/doc/MusicBrainzTag
3536 - u"MusicBrainz Artist Id": "musicbrainz_artistid",
3537 - u"MusicBrainz Album Id": "musicbrainz_albumid",
3538 - u"MusicBrainz Album Artist Id": "musicbrainz_albumartistid",
3539 - u"MusicBrainz TRM Id": "musicbrainz_trmid",
3540 - u"MusicIP PUID": "musicip_puid",
3541 - u"MusicMagic Fingerprint": "musicip_fingerprint",
3542 - u"MusicBrainz Album Status": "musicbrainz_albumstatus",
3543 - u"MusicBrainz Album Type": "musicbrainz_albumtype",
3544 - u"MusicBrainz Album Release Country": "releasecountry",
3545 - u"MusicBrainz Disc Id": "musicbrainz_discid",
3547 - u"ALBUMARTISTSORT": "albumartistsort",
3548 - u"BARCODE": "barcode",
3550 + "MusicBrainz Artist Id": "musicbrainz_artistid",
3551 + "MusicBrainz Album Id": "musicbrainz_albumid",
3552 + "MusicBrainz Album Artist Id": "musicbrainz_albumartistid",
3553 + "MusicBrainz TRM Id": "musicbrainz_trmid",
3554 + "MusicIP PUID": "musicip_puid",
3555 + "MusicMagic Fingerprint": "musicip_fingerprint",
3556 + "MusicBrainz Album Status": "musicbrainz_albumstatus",
3557 + "MusicBrainz Album Type": "musicbrainz_albumtype",
3558 + "MusicBrainz Album Release Country": "releasecountry",
3559 + "MusicBrainz Disc Id": "musicbrainz_discid",
3561 + "ALBUMARTISTSORT": "albumartistsort",
3562 + "BARCODE": "barcode",
3564 EasyID3.RegisterTXXXKey(key, desc)
3566 class EasyID3FileType(ID3FileType):
3567 diff -Naur client175_0.7-original/mutagen/easymp4.py client175_0.7/mutagen/easymp4.py
3568 --- client175_0.7-original/mutagen/easymp4.py 2010-05-15 00:42:14.000000000 +0200
3569 +++ client175_0.7/mutagen/easymp4.py 2021-08-03 14:54:50.039718986 +0200
3573 def getter(tags, key):
3574 - return map(unicode, tags[atomid])
3575 + return list(map(str, tags[atomid]))
3577 def setter(tags, key, value):
3578 clamp = lambda x: int(min(max(min_value, x), max_value))
3579 - tags[atomid] = map(clamp, map(int, value))
3580 + tags[atomid] = list(map(clamp, list(map(int, value))))
3582 def deleter(tags, key):
3586 for (track, total) in tags[atomid]:
3588 - ret.append(u"%d/%d" % (track, total))
3589 + ret.append("%d/%d" % (track, total))
3591 - ret.append(unicode(track))
3592 + ret.append(str(track))
3595 def setter(tags, key, value):
3597 return [s.decode("utf-8", "replace") for s in tags[atomid]]
3599 def setter(tags, key, value):
3600 - tags[atomid] = map(utf8, value)
3601 + tags[atomid] = list(map(utf8, value))
3603 def deleter(tags, key):
3607 def __setitem__(self, key, value):
3609 - if isinstance(value, basestring):
3610 + if isinstance(value, str):
3612 func = dict_match(self.Set, key)
3613 if func is not None:
3618 - for key in self.Get.keys():
3619 + for key in list(self.Get.keys()):
3620 if key in self.List:
3621 keys.extend(self.List[key](self.__mp4, key))
3624 strings.append("%s=%s" % (key, value))
3625 return "\n".join(strings)
3627 -for atomid, key in {
3628 +for atomid, key in list({
3631 '\xa9ART': 'artist',
3632 @@ -211,10 +211,10 @@
3633 'soar': 'artistsort',
3634 'sonm': 'titlesort',
3635 'soco': 'composersort',
3638 EasyMP4Tags.RegisterTextKey(key, atomid)
3641 +for name, key in list({
3642 'MusicBrainz Artist Id': 'musicbrainz_artistid',
3643 'MusicBrainz Track Id': 'musicbrainz_trackid',
3644 'MusicBrainz Album Id': 'musicbrainz_albumid',
3645 @@ -223,18 +223,18 @@
3646 'MusicBrainz Album Status': 'musicbrainz_albumstatus',
3647 'MusicBrainz Album Type': 'musicbrainz_albumtype',
3648 'MusicBrainz Release Country': 'releasecountry',
3651 EasyMP4Tags.RegisterFreeformKey(key, name)
3654 +for name, key in list({
3658 EasyMP4Tags.RegisterIntKey(key, name)
3661 +for name, key in list({
3662 "trkn": "tracknumber",
3663 "disk": "discnumber",
3666 EasyMP4Tags.RegisterIntPairKey(key, name)
3669 diff -Naur client175_0.7-original/mutagen/flac.py client175_0.7/mutagen/flac.py
3670 --- client175_0.7-original/mutagen/flac.py 2010-05-15 00:42:14.000000000 +0200
3671 +++ client175_0.7/mutagen/flac.py 2021-08-03 14:54:56.799621843 +0200
3673 __all__ = ["FLAC", "Open", "delete"]
3676 -from cStringIO import StringIO
3677 -from _vorbis import VCommentDict
3678 +from io import StringIO
3679 +from ._vorbis import VCommentDict
3680 from mutagen import FileType
3681 from mutagen._util import insert_bytes
3682 from mutagen.id3 import BitPaddedInt
3683 +from functools import reduce
3685 class error(IOError): pass
3686 class FLACNoHeaderError(error): pass
3688 def to_int_be(string):
3689 """Convert an arbitrarily-long string to a long using big-endian
3691 - return reduce(lambda a, b: (a << 8) + ord(b), string, 0L)
3692 + return reduce(lambda a, b: (a << 8) + ord(b), string, 0)
3694 class MetadataBlock(object):
3695 """A generic block of FLAC metadata.
3698 The overall size of the rendered blocks does not change, so
3699 this adds several bytes of padding for each merged block."""
3700 - paddings = filter(lambda x: isinstance(x, Padding), blocks)
3701 - map(blocks.remove, paddings)
3702 + paddings = [x for x in blocks if isinstance(x, Padding)]
3703 + list(map(blocks.remove, paddings))
3705 # total padding size is the sum of padding sizes plus 4 bytes
3706 # per removed header.
3708 bps_tail = bps_total >> 36
3709 bps_head = (sample_channels_bps & 1) << 4
3710 self.bits_per_sample = int(bps_head + bps_tail + 1)
3711 - self.total_samples = bps_total & 0xFFFFFFFFFL
3712 + self.total_samples = bps_total & 0xFFFFFFFFF
3713 self.length = self.total_samples / float(self.sample_rate)
3715 self.md5_signature = to_int_be(data.read(16))
3716 @@ -161,12 +162,12 @@
3717 byte += (self.total_samples >> 32) & 0xF
3719 # last 32 of sample count
3720 - f.write(struct.pack(">I", self.total_samples & 0xFFFFFFFFL))
3721 + f.write(struct.pack(">I", self.total_samples & 0xFFFFFFFF))
3723 sig = self.md5_signature
3724 f.write(struct.pack(
3725 - ">4I", (sig >> 96) & 0xFFFFFFFFL, (sig >> 64) & 0xFFFFFFFFL,
3726 - (sig >> 32) & 0xFFFFFFFFL, sig & 0xFFFFFFFFL))
3727 + ">4I", (sig >> 96) & 0xFFFFFFFF, (sig >> 64) & 0xFFFFFFFF,
3728 + (sig >> 32) & 0xFFFFFFFF, sig & 0xFFFFFFFF))
3734 def __init__(self, data=None):
3743 @@ -601,11 +602,10 @@
3745 def clear_pictures(self):
3746 """Delete all pictures from the file."""
3747 - self.metadata_blocks = filter(lambda b: b.code != Picture.code,
3748 - self.metadata_blocks)
3749 + self.metadata_blocks = [b for b in self.metadata_blocks if b.code != Picture.code]
3751 def __get_pictures(self):
3752 - return filter(lambda b: b.code == Picture.code, self.metadata_blocks)
3753 + return [b for b in self.metadata_blocks if b.code == Picture.code]
3754 pictures = property(__get_pictures, doc="List of embedded pictures")
3756 def save(self, filename=None, deleteid3=False):
3757 diff -Naur client175_0.7-original/mutagen/id3.py client175_0.7/mutagen/id3.py
3758 --- client175_0.7-original/mutagen/id3.py 2010-05-15 00:42:14.000000000 +0200
3759 +++ client175_0.7/mutagen/id3.py 2021-08-03 14:55:05.431497226 +0200
3761 raise ValueError('Requested bytes (%s) less than zero' % size)
3762 if size > self.__filesize:
3763 raise EOFError('Requested %#x of %#x (%s)' %
3764 - (long(size), long(self.__filesize), self.filename))
3765 + (int(size), int(self.__filesize), self.filename))
3766 except AttributeError: pass
3767 data = self.__fileobj.read(size)
3768 if len(data) != size: raise EOFError
3769 @@ -115,18 +115,18 @@
3771 raise ID3NoHeaderError("%s: too small (%d bytes)" %(
3772 filename, self.__filesize))
3773 - except (ID3NoHeaderError, ID3UnsupportedVersionError), err:
3774 + except (ID3NoHeaderError, ID3UnsupportedVersionError) as err:
3777 stack = sys.exc_info()[2]
3778 try: self.__fileobj.seek(-128, 2)
3779 - except EnvironmentError: raise err, None, stack
3780 + except EnvironmentError: raise err.with_traceback(stack)
3782 frames = ParseID3v1(self.__fileobj.read(128))
3783 if frames is not None:
3784 self.version = (1, 1)
3785 - map(self.add, frames.values())
3786 - else: raise err, None, stack
3787 + list(map(self.add, list(frames.values())))
3788 + else: raise err.with_traceback(stack)
3790 frames = self.__known_frames
3792 @@ -159,14 +159,14 @@
3793 if key in self: return [self[key]]
3796 - return [v for s,v in self.items() if s.startswith(key)]
3797 + return [v for s,v in list(self.items()) if s.startswith(key)]
3799 def delall(self, key):
3800 """Delete all tags of a given kind; see getall."""
3801 if key in self: del(self[key])
3804 - for k in filter(lambda s: s.startswith(key), self.keys()):
3805 + for k in [s for s in list(self.keys()) if s.startswith(key)]:
3808 def setall(self, key, values):
3810 However, ID3 frames can have multiple keys:
3811 POPM=user@example.org=3 128/255
3813 - return "\n".join(map(Frame.pprint, self.values()))
3814 + return "\n".join(map(Frame.pprint, list(self.values())))
3816 def loaded_frame(self, tag):
3817 """Deprecated; use the add method."""
3820 # Sort frames by 'importance'
3821 order = ["TIT2", "TPE1", "TRCK", "TALB", "TPOS", "TDRC", "TCON"]
3822 - order = dict(zip(order, range(len(order))))
3823 + order = dict(list(zip(order, list(range(len(order))))))
3825 - frames = self.items()
3826 + frames = list(self.items())
3827 frames.sort(lambda a, b: cmp(order.get(a[0][:4], last),
3828 order.get(b[0][:4], last)))
3833 self.delete(filename)
3834 - except EnvironmentError, err:
3835 + except EnvironmentError as err:
3836 from errno import ENOENT
3837 if err.errno != ENOENT: raise
3841 if filename is None: filename = self.filename
3842 try: f = open(filename, 'rb+')
3843 - except IOError, err:
3844 + except IOError as err:
3845 from errno import ENOENT
3846 if err.errno != ENOENT: raise
3847 f = open(filename, 'ab') # create, then reopen
3852 - except IOError, err:
3853 + except IOError as err:
3854 from errno import EINVAL
3855 if err.errno != EINVAL: raise
3856 f.seek(0, 2) # ensure read won't get "TAG"
3858 def __new__(cls, value, bits=7, bigendian=True):
3859 "Strips 8-bits bits out of every byte"
3860 mask = (1<<(bits))-1
3861 - if isinstance(value, (int, long)):
3862 + if isinstance(value, int):
3865 bytes.append(value & ((1<<bits)-1))
3866 @@ -549,10 +549,10 @@
3867 bytes = [ord(byte) & mask for byte in value]
3868 if bigendian: bytes.reverse()
3870 - for shift, byte in zip(range(0, len(bytes)*bits, bits), bytes):
3871 + for shift, byte in zip(list(range(0, len(bytes)*bits, bits)), bytes):
3872 numeric_value += byte << shift
3873 - if isinstance(numeric_value, long):
3874 - self = long.__new__(BitPaddedLong, numeric_value)
3875 + if isinstance(numeric_value, int):
3876 + self = int.__new__(BitPaddedLong, numeric_value)
3878 self = int.__new__(BitPaddedInt, numeric_value)
3881 # PCNT and POPM use growing integers of at least 4 bytes as counters.
3882 if width == -1: width = max(4, len(bytes))
3883 if len(bytes) > width:
3884 - raise ValueError, 'Value too wide (%d bytes)' % len(bytes)
3885 + raise ValueError('Value too wide (%d bytes)' % len(bytes))
3886 else: bytes.extend([0] * (width-len(bytes)))
3887 if bigendian: bytes.reverse()
3888 return ''.join(map(chr, bytes))
3890 def validate(self, frame, value):
3891 if 0 <= value <= 3: return value
3892 if value is None: return None
3893 - raise ValueError, 'Invalid Encoding: %r' % value
3894 + raise ValueError('Invalid Encoding: %r' % value)
3896 class StringSpec(Spec):
3897 def __init__(self, name, length):
3899 else: return (str(value) + '\x00' * s.len)[:s.len]
3900 def validate(s, frame, value):
3901 if value is None: return None
3902 - if isinstance(value, basestring) and len(value) == s.len: return value
3903 - raise ValueError, 'Invalid StringSpec[%d] data: %r' % (s.len, value)
3904 + if isinstance(value, str) and len(value) == s.len: return value
3905 + raise ValueError('Invalid StringSpec[%d] data: %r' % (s.len, value))
3907 class BinaryDataSpec(Spec):
3908 def read(self, frame, data): return data, ''
3909 @@ -696,14 +696,14 @@
3910 data, ret = data[0:offset], data[offset+2:]; break
3911 except ValueError: pass
3913 - if len(data) < len(term): return u'', ret
3914 + if len(data) < len(term): return '', ret
3915 return data.decode(enc), ret
3917 def write(self, frame, value):
3918 enc, term = self._encodings[frame.encoding]
3919 return value.encode(enc) + term
3921 - def validate(self, frame, value): return unicode(value)
3922 + def validate(self, frame, value): return str(value)
3924 class MultiSpec(Spec):
3925 def __init__(self, name, *specs, **kw):
3928 def validate(self, frame, value):
3929 if value is None: return []
3930 - if self.sep and isinstance(value, basestring):
3931 + if self.sep and isinstance(value, str):
3932 value = value.split(self.sep)
3933 if isinstance(value, list):
3934 if len(self.specs) == 1:
3937 [s.validate(frame, v) for (v,s) in zip(val, self.specs)]
3939 - raise ValueError, 'Invalid MultiSpec data: %r' % value
3940 + raise ValueError('Invalid MultiSpec data: %r' % value)
3942 class EncodedNumericTextSpec(EncodedTextSpec): pass
3943 class EncodedNumericPartTextSpec(EncodedTextSpec): pass
3945 def write(self, data, value):
3946 return value.encode('latin1') + '\x00'
3948 - def validate(self, frame, value): return unicode(value)
3949 + def validate(self, frame, value): return str(value)
3951 class ID3TimeStamp(object):
3952 """A time stamp in ID3v2 format.
3954 parts = [self.year, self.month, self.day,
3955 self.hour, self.minute, self.second]
3957 - for i, part in enumerate(iter(iter(parts).next, None)):
3958 + for i, part in enumerate(iter(iter(parts).__next__, None)):
3959 pieces.append(self.__formats[i]%part + self.__seps[i])
3960 - return u''.join(pieces)[:-1]
3961 + return ''.join(pieces)[:-1]
3963 def set_text(self, text, splitre=re.compile('[-T:/.]|\s+')):
3964 year, month, day, hour, minute, second = \
3965 @@ -812,11 +812,11 @@
3967 def validate(self, frame, value):
3968 try: return ID3TimeStamp(value)
3969 - except TypeError: raise ValueError, "Invalid ID3TimeStamp: %r" % value
3970 + except TypeError: raise ValueError("Invalid ID3TimeStamp: %r" % value)
3972 class ChannelSpec(ByteSpec):
3973 (OTHER, MASTER, FRONTRIGHT, FRONTLEFT, BACKRIGHT, BACKLEFT, FRONTCENTRE,
3974 - BACKCENTRE, SUBWOOFER) = range(9)
3975 + BACKCENTRE, SUBWOOFER) = list(range(9))
3977 class VolumeAdjustmentSpec(Spec):
3978 def read(self, frame, data):
3982 adjustments[freq] = adj
3983 - adjustments = adjustments.items()
3984 + adjustments = list(adjustments.items())
3986 return adjustments, data
3988 @@ -1033,21 +1033,21 @@
3990 if tflags & Frame.FLAG24_UNSYNCH or id3.f_unsynch:
3991 try: data = unsynch.decode(data)
3992 - except ValueError, err:
3993 + except ValueError as err:
3995 - raise ID3BadUnsynchData, '%s: %r' % (err, data)
3996 + raise ID3BadUnsynchData('%s: %r' % (err, data))
3997 if tflags & Frame.FLAG24_ENCRYPT:
3998 raise ID3EncryptionUnsupportedError
3999 if tflags & Frame.FLAG24_COMPRESS:
4000 try: data = data.decode('zlib')
4001 - except zlibError, err:
4002 + except zlibError as err:
4003 # the initial mutagen that went out with QL 0.12 did not
4004 # write the 4 bytes of uncompressed size. Compensate.
4005 data = datalen_bytes + data
4006 try: data = data.decode('zlib')
4007 - except zlibError, err:
4008 + except zlibError as err:
4010 - raise ID3BadCompressedData, '%s: %r' % (err, data)
4011 + raise ID3BadCompressedData('%s: %r' % (err, data))
4013 elif (2,3,0) <= id3.version:
4014 if tflags & Frame.FLAG23_COMPRESS:
4015 @@ -1057,9 +1057,9 @@
4016 raise ID3EncryptionUnsupportedError
4017 if tflags & Frame.FLAG23_COMPRESS:
4018 try: data = data.decode('zlib')
4019 - except zlibError, err:
4020 + except zlibError as err:
4022 - raise ID3BadCompressedData, '%s: %r' % (err, data)
4023 + raise ID3BadCompressedData('%s: %r' % (err, data))
4026 frame._rawdata = data
4027 @@ -1138,12 +1138,12 @@
4030 _framespec = [ EncodingSpec('encoding'),
4031 - MultiSpec('text', EncodedTextSpec('text'), sep=u'\u0000') ]
4032 + MultiSpec('text', EncodedTextSpec('text'), sep='\u0000') ]
4033 def __str__(self): return self.__unicode__().encode('utf-8')
4034 - def __unicode__(self): return u'\u0000'.join(self.text)
4035 + def __unicode__(self): return '\u0000'.join(self.text)
4036 def __eq__(self, other):
4037 if isinstance(other, str): return str(self) == other
4038 - elif isinstance(other, unicode): return unicode(self) == other
4039 + elif isinstance(other, str): return str(self) == other
4040 return self.text == other
4041 def __getitem__(self, item): return self.text[item]
4042 def __iter__(self): return iter(self.text)
4043 @@ -1160,7 +1160,7 @@
4046 _framespec = [ EncodingSpec('encoding'),
4047 - MultiSpec('text', EncodedNumericTextSpec('text'), sep=u'\u0000') ]
4048 + MultiSpec('text', EncodedNumericTextSpec('text'), sep='\u0000') ]
4051 """Return the numerical value of the string."""
4052 @@ -1176,7 +1176,7 @@
4055 _framespec = [ EncodingSpec('encoding'),
4056 - MultiSpec('text', EncodedNumericPartTextSpec('text'), sep=u'\u0000') ]
4057 + MultiSpec('text', EncodedNumericPartTextSpec('text'), sep='\u0000') ]
4059 return int(self.text[0].split("/")[0])
4061 @@ -1188,7 +1188,7 @@
4064 _framespec = [ EncodingSpec('encoding'),
4065 - MultiSpec('text', TimeStampSpec('stamp'), sep=u',') ]
4066 + MultiSpec('text', TimeStampSpec('stamp'), sep=',') ]
4067 def __str__(self): return self.__unicode__().encode('utf-8')
4068 def __unicode__(self): return ','.join([stamp.text for stamp in self.text])
4070 @@ -1235,9 +1235,9 @@
4071 for value in self.text:
4073 try: genres.append(self.GENRES[int(value)])
4074 - except IndexError: genres.append(u"Unknown")
4075 - elif value == "CR": genres.append(u"Cover")
4076 - elif value == "RX": genres.append(u"Remix")
4077 + except IndexError: genres.append("Unknown")
4078 + elif value == "CR": genres.append("Cover")
4079 + elif value == "RX": genres.append("Remix")
4082 genreid, dummy, genrename = genre_re.match(value).groups()
4083 @@ -1245,11 +1245,11 @@
4085 for gid in genreid[1:-1].split(")("):
4086 if gid.isdigit() and int(gid) < len(self.GENRES):
4087 - gid = unicode(self.GENRES[int(gid)])
4088 + gid = str(self.GENRES[int(gid)])
4089 newgenres.append(gid)
4090 - elif gid == "CR": newgenres.append(u"Cover")
4091 - elif gid == "RX": newgenres.append(u"Remix")
4092 - else: newgenres.append(u"Unknown")
4093 + elif gid == "CR": newgenres.append("Cover")
4094 + elif gid == "RX": newgenres.append("Remix")
4095 + else: newgenres.append("Unknown")
4098 # "Unescaping" the first parenthesis
4099 @@ -1261,8 +1261,8 @@
4102 def __set_genres(self, genres):
4103 - if isinstance(genres, basestring): genres = [genres]
4104 - self.text = map(self.__decode, genres)
4105 + if isinstance(genres, str): genres = [genres]
4106 + self.text = list(map(self.__decode, genres))
4108 def __decode(self, value):
4109 if isinstance(value, str):
4110 @@ -1333,7 +1333,7 @@
4111 the same). Many taggers use this frame to store freeform keys.
4113 _framespec = [ EncodingSpec('encoding'), EncodedTextSpec('desc'),
4114 - MultiSpec('text', EncodedTextSpec('text'), sep=u'\u0000') ]
4115 + MultiSpec('text', EncodedTextSpec('text'), sep='\u0000') ]
4116 HashKey = property(lambda s: '%s:%s' % (s.FrameID, s.desc))
4117 def _pprint(self): return "%s=%s" % (self.desc, " / ".join(self.text))
4119 @@ -1448,7 +1448,7 @@
4121 _framespec = [ EncodingSpec('encoding'), StringSpec('lang', 3),
4122 EncodedTextSpec('desc'),
4123 - MultiSpec('text', EncodedTextSpec('text'), sep=u'\u0000') ]
4124 + MultiSpec('text', EncodedTextSpec('text'), sep='\u0000') ]
4125 HashKey = property(lambda s: '%s:%s:%r' % (s.FrameID, s.desc, s.lang))
4126 def _pprint(self): return "%s=%r=%s" % (
4127 self.desc, self.lang, " / ".join(self.text))
4128 @@ -1545,7 +1545,7 @@
4130 def __eq__(self, other): return self.count == other
4131 def __pos__(self): return self.count
4132 - def _pprint(self): return unicode(self.count)
4133 + def _pprint(self): return str(self.count)
4135 class POPM(FrameOpt):
4137 @@ -1774,7 +1774,7 @@
4138 ASPIIndexSpec("Fi") ]
4139 def __eq__(self, other): return self.Fi == other
4141 -Frames = dict([(k,v) for (k,v) in globals().items()
4142 +Frames = dict([(k,v) for (k,v) in list(globals().items())
4143 if len(k)==4 and isinstance(v, type) and issubclass(v, Frame)])
4144 """All supported ID3v2 frames, keyed by frame name."""
4146 @@ -1867,7 +1867,7 @@
4147 _framespec = [ StringSpec('frameid', 3), Latin1TextSpec('url') ]
4148 _optionalspec = [ BinaryDataSpec('data') ]
4150 -Frames_2_2 = dict([(k,v) for (k,v) in globals().items()
4151 +Frames_2_2 = dict([(k,v) for (k,v) in list(globals().items())
4152 if len(k)==3 and isinstance(v, type) and issubclass(v, Frame)])
4154 # support open(filename) as interface
4155 @@ -1886,8 +1886,8 @@
4156 if tag != "TAG": return None
4158 return string.split("\x00")[0].strip().decode('latin1')
4159 - title, artist, album, year, comment = map(
4160 - fix, [title, artist, album, year, comment])
4161 + title, artist, album, year, comment = list(map(
4162 + fix, [title, artist, album, year, comment]))
4164 if title: frames["TIT2"] = TIT2(encoding=0, text=title)
4165 if artist: frames["TPE1"] = TPE1(encoding=0, text=[artist])
4166 @@ -1907,8 +1907,8 @@
4170 - for v2id, name in {"TIT2": "title", "TPE1": "artist",
4171 - "TALB": "album"}.items():
4172 + for v2id, name in list({"TIT2": "title", "TPE1": "artist",
4173 + "TALB": "album"}.items()):
4175 text = id3[v2id].text[0].encode('latin1', 'replace')[:30]
4177 diff -Naur client175_0.7-original/mutagen/__init__.py client175_0.7/mutagen/__init__.py
4178 --- client175_0.7-original/mutagen/__init__.py 2010-05-15 00:42:14.000000000 +0200
4179 +++ client175_0.7/mutagen/__init__.py 2021-08-03 14:55:18.899303101 +0200
4182 If the file has no tags at all, a KeyError is raised.
4184 - if self.tags is None: raise KeyError, key
4185 + if self.tags is None: raise KeyError(key)
4186 else: return self.tags[key]
4188 def __setitem__(self, key, value):
4191 If the file has no tags at all, a KeyError is raised.
4193 - if self.tags is None: raise KeyError, key
4194 + if self.tags is None: raise KeyError(key)
4195 else: del(self.tags[key])
4199 If the file has no tags at all, an empty list is returned.
4201 if self.tags is None: return []
4202 - else: return self.tags.keys()
4203 + else: return list(self.tags.keys())
4205 def delete(self, filename=None):
4206 """Remove tags from a file."""
4208 for Kind in options]
4211 - results = zip(results, options)
4212 + results = list(zip(results, options))
4214 (score, name), Kind = results[-1]
4215 if score > 0: return Kind(filename)
4216 diff -Naur client175_0.7-original/mutagen/m4a.py client175_0.7/mutagen/m4a.py
4217 --- client175_0.7-original/mutagen/m4a.py 2010-05-15 00:42:14.000000000 +0200
4218 +++ client175_0.7/mutagen/m4a.py 2021-08-03 14:55:39.954998104 +0200
4223 -from cStringIO import StringIO
4224 +from io import StringIO
4226 from mutagen import FileType, Metadata
4227 from mutagen._constants import GENRES
4229 if child.name == remaining[0]:
4230 return child[remaining[1:]]
4232 - raise KeyError, "%r not found" % remaining[0]
4233 + raise KeyError("%r not found" % remaining[0])
4236 klass = self.__class__.__name__
4237 @@ -166,13 +166,13 @@
4238 'names' may be a list of atoms (['moov', 'udta']) or a string
4239 specifying the complete path ('moov.udta').
4241 - if isinstance(names, basestring):
4242 + if isinstance(names, str):
4243 names = names.split(".")
4244 for child in self.atoms:
4245 if child.name == names[0]:
4246 return child[names[1:]]
4248 - raise KeyError, "%s not found" % names[0]
4249 + raise KeyError("%s not found" % names[0])
4252 return "\n".join([repr(child) for child in self.atoms])
4255 def load(self, atoms, fileobj):
4256 try: ilst = atoms["moov.udta.meta.ilst"]
4257 - except KeyError, key:
4258 + except KeyError as key:
4259 raise M4AMetadataError(key)
4260 for atom in ilst.children:
4261 fileobj.seek(atom.offset + 8)
4262 @@ -210,14 +210,16 @@
4263 parse = self.__atoms.get(atom.name, (M4ATags.__parse_text,))[0]
4264 parse(self, atom, data)
4266 - def __key_sort((key1, v1), (key2, v2)):
4267 + def __key_sort(xxx_todo_changeme, xxx_todo_changeme1):
4268 # iTunes always writes the tags in order of "relevance", try
4269 # to copy it as closely as possible.
4270 + (key1, v1) = xxx_todo_changeme
4271 + (key2, v2) = xxx_todo_changeme1
4272 order = ["\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb",
4273 "\xa9gen", "gnre", "trkn", "disk",
4274 "\xa9day", "cpil", "tmpo", "\xa9too",
4275 "----", "covr", "\xa9lyr"]
4276 - order = dict(zip(order, range(len(order))))
4277 + order = dict(list(zip(order, list(range(len(order))))))
4279 # If there's no key-based way to distinguish, order by length.
4280 # If there's still no way, go by string comparison on the
4282 def save(self, filename):
4283 """Save the metadata to the given filename."""
4285 - items = self.items()
4286 + items = list(self.items())
4287 items.sort(self.__key_sort)
4288 for key, value in items:
4289 render = self.__atoms.get(
4294 - for key, value in self.iteritems():
4295 + for key, value in self.items():
4296 key = key.decode('latin1')
4297 try: values.append("%s=%s" % (key, value))
4298 except UnicodeDecodeError:
4299 @@ -475,13 +477,13 @@
4301 atoms = Atoms(fileobj)
4302 try: self.info = M4AInfo(atoms, fileobj)
4303 - except StandardError, err:
4304 - raise M4AStreamInfoError, err, sys.exc_info()[2]
4305 + except Exception as err:
4306 + raise M4AStreamInfoError(err).with_traceback(sys.exc_info()[2])
4307 try: self.tags = M4ATags(atoms, fileobj)
4308 except M4AMetadataError:
4310 - except StandardError, err:
4311 - raise M4AMetadataError, err, sys.exc_info()[2]
4312 + except Exception as err:
4313 + raise M4AMetadataError(err).with_traceback(sys.exc_info()[2])
4317 diff -Naur client175_0.7-original/mutagen/mp3.py client175_0.7/mutagen/mp3.py
4318 --- client175_0.7-original/mutagen/mp3.py 2010-05-15 00:42:14.000000000 +0200
4319 +++ client175_0.7/mutagen/mp3.py 2021-08-03 14:55:59.774710002 +0200
4321 class InvalidMPEGHeader(error, IOError): pass
4324 -STEREO, JOINTSTEREO, DUALCHANNEL, MONO = range(4)
4325 +STEREO, JOINTSTEREO, DUALCHANNEL, MONO = list(range(4))
4327 class MPEGInfo(object):
4328 """MPEG audio stream information
4331 # Map (version, layer) tuples to bitrates.
4333 - (1, 1): range(0, 480, 32),
4334 + (1, 1): list(range(0, 480, 32)),
4335 (1, 2): [0, 32, 48, 56, 64, 80, 96, 112,128,160,192,224,256,320,384],
4336 (1, 3): [0, 32, 40, 48, 56, 64, 80, 96, 112,128,160,192,224,256,320],
4337 (2, 1): [0, 32, 48, 56, 64, 80, 96, 112,128,144,160,176,192,224,256],
4339 # and 90% through the file.
4340 for i in [offset, 0.3 * size, 0.6 * size, 0.9 * size]:
4341 try: self.__try(fileobj, int(i), size - offset)
4342 - except error, e: pass
4343 + except error as e: pass
4345 # If we can't find any two consecutive frames, try to find just
4346 # one frame back at the original offset given.
4347 diff -Naur client175_0.7-original/mutagen/mp4.py client175_0.7/mutagen/mp4.py
4348 --- client175_0.7-original/mutagen/mp4.py 2010-05-15 00:42:14.000000000 +0200
4349 +++ client175_0.7/mutagen/mp4.py 2021-08-03 14:56:05.542625890 +0200
4351 if child.name == remaining[0]:
4352 return child[remaining[1:]]
4354 - raise KeyError, "%r not found" % remaining[0]
4355 + raise KeyError("%r not found" % remaining[0])
4358 klass = self.__class__.__name__
4359 @@ -168,13 +168,13 @@
4360 'names' may be a list of atoms (['moov', 'udta']) or a string
4361 specifying the complete path ('moov.udta').
4363 - if isinstance(names, basestring):
4364 + if isinstance(names, str):
4365 names = names.split(".")
4366 for child in self.atoms:
4367 if child.name == names[0]:
4368 return child[names[1:]]
4370 - raise KeyError, "%s not found" % names[0]
4371 + raise KeyError("%s not found" % names[0])
4374 return "\n".join([repr(child) for child in self.atoms])
4377 def load(self, atoms, fileobj):
4378 try: ilst = atoms["moov.udta.meta.ilst"]
4379 - except KeyError, key:
4380 + except KeyError as key:
4381 raise MP4MetadataError(key)
4382 for atom in ilst.children:
4383 fileobj.seek(atom.offset + 8)
4384 @@ -250,14 +250,16 @@
4385 info = self.__atoms.get(atom.name, (type(self).__parse_text, None))
4386 info[0](self, atom, data, *info[2:])
4388 - def __key_sort((key1, v1), (key2, v2)):
4389 + def __key_sort(xxx_todo_changeme, xxx_todo_changeme1):
4390 # iTunes always writes the tags in order of "relevance", try
4391 # to copy it as closely as possible.
4392 + (key1, v1) = xxx_todo_changeme
4393 + (key2, v2) = xxx_todo_changeme1
4394 order = ["\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb",
4395 "\xa9gen", "gnre", "trkn", "disk",
4396 "\xa9day", "cpil", "pgap", "pcst", "tmpo",
4397 "\xa9too", "----", "covr", "\xa9lyr"]
4398 - order = dict(zip(order, range(len(order))))
4399 + order = dict(list(zip(order, list(range(len(order))))))
4401 # If there's no key-based way to distinguish, order by length.
4402 # If there's still no way, go by string comparison on the
4403 @@ -269,14 +271,14 @@
4404 def save(self, filename):
4405 """Save the metadata to the given filename."""
4407 - items = self.items()
4408 + items = list(self.items())
4409 items.sort(self.__key_sort)
4410 for key, value in items:
4411 info = self.__atoms.get(key[:4], (None, type(self).__render_text))
4413 values.append(info[1](self, key, value, *info[2:]))
4414 - except (TypeError, ValueError), s:
4415 - raise MP4MetadataValueError, s, sys.exc_info()[2]
4416 + except (TypeError, ValueError) as s:
4417 + raise MP4MetadataValueError(s).with_traceback(sys.exc_info()[2])
4418 data = Atom.render("ilst", "".join(values))
4420 # Find the old atoms.
4422 dummy, mean, name = key.split(":", 2)
4423 mean = struct.pack(">I4sI", len(mean) + 12, "mean", 0) + mean
4424 name = struct.pack(">I4sI", len(name) + 12, "name", 0) + name
4425 - if isinstance(value, basestring):
4426 + if isinstance(value, str):
4428 return Atom.render("----", mean + name + "".join([
4429 struct.pack(">I4s2I", len(data) + 16, "data", 1, 0) + data
4431 raise MP4MetadataValueError(
4432 "tmpo must be a list of 16 bit integers")
4434 - values = map(cdata.to_ushort_be, value)
4435 + values = list(map(cdata.to_ushort_be, value))
4436 return self.__render_data(key, 0x15, values)
4438 def __parse_bool(self, atom, data):
4439 @@ -531,10 +533,10 @@
4441 self[atom.name] = value
4442 def __render_text(self, key, value, flags=1):
4443 - if isinstance(value, basestring):
4444 + if isinstance(value, str):
4446 return self.__render_data(
4447 - key, flags, map(utf8, value))
4448 + key, flags, list(map(utf8, value)))
4450 def delete(self, filename):
4452 @@ -556,13 +558,13 @@
4456 - for key, value in self.iteritems():
4457 + for key, value in self.items():
4458 key = key.decode('latin1')
4460 values.append("%s=%s" % (key, ", ".join(
4461 ["[%d bytes of data]" % len(data) for data in value])))
4462 elif isinstance(value, list):
4463 - values.append("%s=%s" % (key, " / ".join(map(unicode, value))))
4464 + values.append("%s=%s" % (key, " / ".join(map(str, value))))
4466 values.append("%s=%s" % (key, value))
4467 return "\n".join(values)
4468 @@ -658,13 +660,13 @@
4470 atoms = Atoms(fileobj)
4471 try: self.info = MP4Info(atoms, fileobj)
4472 - except StandardError, err:
4473 - raise MP4StreamInfoError, err, sys.exc_info()[2]
4474 + except Exception as err:
4475 + raise MP4StreamInfoError(err).with_traceback(sys.exc_info()[2])
4476 try: self.tags = self.MP4Tags(atoms, fileobj)
4477 except MP4MetadataError:
4479 - except StandardError, err:
4480 - raise MP4MetadataError, err, sys.exc_info()[2]
4481 + except Exception as err:
4482 + raise MP4MetadataError(err).with_traceback(sys.exc_info()[2])
4486 diff -Naur client175_0.7-original/mutagen/oggflac.py client175_0.7/mutagen/oggflac.py
4487 --- client175_0.7-original/mutagen/oggflac.py 2010-05-15 00:42:14.000000000 +0200
4488 +++ client175_0.7/mutagen/oggflac.py 2021-08-03 14:56:29.786272048 +0200
4493 -from cStringIO import StringIO
4494 +from io import StringIO
4496 from mutagen.flac import StreamInfo, VCFLACDict
4497 from mutagen.ogg import OggPage, OggFileType, error as OggError
4498 diff -Naur client175_0.7-original/mutagen/ogg.py client175_0.7/mutagen/ogg.py
4499 --- client175_0.7-original/mutagen/ogg.py 2010-05-15 00:42:14.000000000 +0200
4500 +++ client175_0.7/mutagen/ogg.py 2021-08-03 14:56:22.722375298 +0200
4505 -from cStringIO import StringIO
4506 +from io import StringIO
4508 from mutagen import FileType
4509 from mutagen._util import cdata, insert_bytes, delete_bytes
4520 lacings.append(total)
4521 self.complete = False
4523 - self.packets = map(fileobj.read, lacings)
4524 - if map(len, self.packets) != lacings:
4525 + self.packets = list(map(fileobj.read, lacings))
4526 + if list(map(len, self.packets)) != lacings:
4527 raise error("unable to read full data")
4529 def __eq__(self, other):
4531 if page.packets[-1]:
4532 page.complete = False
4533 if len(page.packets) == 1:
4534 - page.position = -1L
4535 + page.position = -1
4537 page.packets.pop(-1)
4541 # Number the new pages starting from the first old page.
4542 first = old_pages[0].sequence
4543 - for page, seq in zip(new_pages, range(first, first + len(new_pages))):
4544 + for page, seq in zip(new_pages, list(range(first, first + len(new_pages)))):
4546 page.serial = old_pages[0].serial
4549 new_pages[-1].last = old_pages[-1].last
4550 new_pages[-1].complete = old_pages[-1].complete
4551 if not new_pages[-1].complete and len(new_pages[-1].packets) == 1:
4552 - new_pages[-1].position = -1L
4553 + new_pages[-1].position = -1
4555 new_data = "".join(map(klass.write, new_pages))
4557 @@ -454,10 +454,10 @@
4558 denom = self.info.fps
4559 self.info.length = samples / float(denom)
4562 - raise self._Error, e, sys.exc_info()[2]
4563 + except error as e:
4564 + raise self._Error(e).with_traceback(sys.exc_info()[2])
4566 - raise self._Error, "no appropriate stream found"
4567 + raise self._Error("no appropriate stream found")
4571 @@ -473,10 +473,10 @@
4572 fileobj = file(filename, "rb+")
4574 try: self.tags._inject(fileobj)
4576 - raise self._Error, e, sys.exc_info()[2]
4577 + except error as e:
4578 + raise self._Error(e).with_traceback(sys.exc_info()[2])
4580 - raise self._Error, "no appropriate stream found"
4581 + raise self._Error("no appropriate stream found")
4586 fileobj = file(filename, "rb+")
4588 try: self.tags._inject(fileobj)
4590 - raise self._Error, e, sys.exc_info()[2]
4591 + except error as e:
4592 + raise self._Error(e).with_traceback(sys.exc_info()[2])
4594 - raise self._Error, "no appropriate stream found"
4595 + raise self._Error("no appropriate stream found")
4598 diff -Naur client175_0.7-original/mutagen/_util.py client175_0.7/mutagen/_util.py
4599 --- client175_0.7-original/mutagen/_util.py 2010-05-15 00:42:14.000000000 +0200
4600 +++ client175_0.7/mutagen/_util.py 2021-08-03 14:57:18.085567569 +0200
4605 - return iter(self.keys())
4606 + return iter(list(self.keys()))
4608 def has_key(self, key):
4612 __contains__ = has_key
4614 - iterkeys = lambda self: iter(self.keys())
4615 + iterkeys = lambda self: iter(list(self.keys()))
4618 - return map(self.__getitem__, self.keys())
4619 - itervalues = lambda self: iter(self.values())
4620 + return list(map(self.__getitem__, list(self.keys())))
4621 + itervalues = lambda self: iter(list(self.values()))
4624 - return zip(self.keys(), self.values())
4625 - iteritems = lambda s: iter(s.items())
4626 + return list(zip(list(self.keys()), list(self.values())))
4627 + iteritems = lambda s: iter(list(s.items()))
4630 - map(self.__delitem__, self.keys())
4631 + list(map(self.__delitem__, list(self.keys())))
4633 def pop(self, key, *args):
4639 - key = self.keys()[0]
4640 + key = list(self.keys())[0]
4641 return key, self.pop(key)
4642 except IndexError: raise KeyError("dictionary is empty")
4648 - try: map(self.__setitem__, other.keys(), other.values())
4649 + try: list(map(self.__setitem__, list(other.keys()), list(other.values())))
4650 except AttributeError:
4651 for key, value in other:
4654 except KeyError: return default
4657 - return repr(dict(self.items()))
4658 + return repr(dict(list(self.items())))
4660 def __cmp__(self, other):
4661 if other is None: return 1
4662 - else: return cmp(dict(self.items()), other)
4663 + else: return cmp(dict(list(self.items())), other)
4666 - return len(self.keys())
4667 + return len(list(self.keys()))
4669 class DictProxy(DictMixin):
4670 def __init__(self, *args, **kwargs):
4672 del(self.__dict[key])
4675 - return self.__dict.keys()
4676 + return list(self.__dict.keys())
4678 class cdata(object):
4679 """C character buffer to Python numeric type conversions."""
4681 """Convert a basestring to a valid UTF-8 str."""
4682 if isinstance(data, str):
4683 return data.decode("utf-8", "replace").encode("utf-8")
4684 - elif isinstance(data, unicode):
4685 + elif isinstance(data, str):
4686 return data.encode("utf-8")
4687 else: raise TypeError("only unicode/str types can be converted to UTF-8")
4693 - for pattern, value in d.iteritems():
4694 + for pattern, value in d.items():
4695 if fnmatchcase(key, pattern):
4698 diff -Naur client175_0.7-original/mutagen/_vorbis.py client175_0.7/mutagen/_vorbis.py
4699 --- client175_0.7-original/mutagen/_vorbis.py 2010-05-15 00:42:14.000000000 +0200
4700 +++ client175_0.7/mutagen/_vorbis.py 2021-08-03 14:57:26.321443147 +0200
4705 -from cStringIO import StringIO
4706 +from io import StringIO
4709 from mutagen._util import DictMixin, cdata
4711 vendor -- the stream 'vendor' (i.e. writer); default 'Mutagen'
4714 - vendor = u"Mutagen " + mutagen.version_string
4715 + vendor = "Mutagen " + mutagen.version_string
4717 def __init__(self, data=None, *args, **kwargs):
4718 # Collect the args to pass to load, this lets child classes
4720 except (OverflowError, MemoryError):
4721 raise error("cannot read %d bytes, too large" % length)
4722 try: tag, value = string.split('=', 1)
4723 - except ValueError, err:
4724 + except ValueError as err:
4725 if errors == "ignore":
4727 elif errors == "replace":
4728 - tag, value = u"unknown%d" % i, string
4729 + tag, value = "unknown%d" % i, string
4731 - raise VorbisEncodingError, str(err), sys.exc_info()[2]
4732 + raise VorbisEncodingError(str(err)).with_traceback(sys.exc_info()[2])
4733 try: tag = tag.encode('ascii', errors)
4734 except UnicodeEncodeError:
4735 - raise VorbisEncodingError, "invalid tag name %r" % tag
4736 + raise VorbisEncodingError("invalid tag name %r" % tag)
4738 if is_valid_key(tag): self.append((tag, value))
4739 if framing and not ord(fileobj.read(1)) & 0x01:
4741 any invalid keys or values are found, a ValueError is raised.
4744 - if not isinstance(self.vendor, unicode):
4745 + if not isinstance(self.vendor, str):
4746 try: self.vendor.decode('utf-8')
4747 except UnicodeDecodeError: raise ValueError
4751 if not is_valid_key(key): raise ValueError
4752 except: raise ValueError("%r is not a valid key" % key)
4753 - if not isinstance(value, unicode):
4754 + if not isinstance(value, str):
4755 try: value.encode("utf-8")
4756 except: raise ValueError("%r is not a valid value" % value)
4758 @@ -181,15 +181,15 @@
4760 key = key.lower().encode('ascii')
4761 values = [value for (k, value) in self if k.lower() == key]
4762 - if not values: raise KeyError, key
4763 + if not values: raise KeyError(key)
4766 def __delitem__(self, key):
4767 """Delete all values associated with the key."""
4768 key = key.lower().encode('ascii')
4769 - to_delete = filter(lambda x: x[0].lower() == key, self)
4770 - if not to_delete:raise KeyError, key
4771 - else: map(self.remove, to_delete)
4772 + to_delete = [x for x in self if x[0].lower() == key]
4773 + if not to_delete:raise KeyError(key)
4774 + else: list(map(self.remove, to_delete))
4776 def __contains__(self, key):
4777 """Return true if the key has any values."""
4781 """Return a copy of the comment data in a real dict."""
4782 - return dict((key, self[key]) for key in self.keys())
4783 + return dict((key, self[key]) for key in list(self.keys()))
4784 diff -Naur client175_0.7-original/server.py client175_0.7/server.py
4785 --- client175_0.7-original/server.py 2011-04-06 13:18:04.000000000 +0200
4786 +++ client175_0.7/server.py 2021-08-03 14:40:26.132681859 +0200
4788 # MA 02110-1301, USA.
4791 -import cherrypy, json, os, pwd, urllib, urllib2, sys
4792 +import cherrypy, json, os, pwd, urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, sys
4793 from BeautifulSoup import BeautifulSoup
4794 from time import sleep
4795 from datetime import datetime, timedelta
4798 RUN_AS = pwd.getpwuid(os.getuid())[0]
4800 -if os.environ.has_key("MPD_HOST"):
4801 +if "MPD_HOST" in os.environ:
4802 mpd_host = str(os.environ["MPD_HOST"])
4804 mpd_host = mpd_host.split("@")
4809 -if os.environ.has_key("MPD_PORT"):
4810 +if "MPD_PORT" in os.environ:
4811 PORT = int(os.environ["MPD_PORT"])
4813 HOST = cherrypy.config.get('mpd_host', HOST)
4816 def add(self, *args, **kwargs):
4818 - args = list(args) + kwargs.values()
4819 + args = list(args) + list(kwargs.values())
4821 if args[0] in ('file', 'directory'):
4824 if ext in ['mp3', 'pgg', 'wav', 'flac', 'aac', 'mod', 'wma']:
4827 - sock = urllib2.urlopen(d)
4828 + sock = urllib.request.urlopen(d)
4831 mime = info.gettype()
4832 @@ -201,13 +201,13 @@
4836 - args = list(args) + kwargs.values()
4837 + args = list(args) + list(kwargs.values())
4843 result = mpd.execute(args)
4844 - except MPDError, e:
4845 + except MPDError as e:
4846 raise cherrypy.HTTPError(501, message=str(e))
4847 return json.dumps(result)
4848 default.exposed = True
4850 return "WAV editing not supported."
4853 - for tag, val in kwargs.items():
4854 + for tag, val in list(kwargs.items()):
4857 tags['tracknumber'] = val
4859 tags['discnumber'] = val
4862 - print '%s[%s] = "%s"' % (id, tag, val)
4863 + print('%s[%s] = "%s"' % (id, tag, val))
4865 f = metadata.get_format(loc)
4871 - except MPDError, e:
4872 + except MPDError as e:
4873 if str(e) == "[54@0] {update} already updating":
4878 skip = ('type', 'time', 'ptime', 'songs')
4880 - for key, val in item.items():
4881 + for key, val in list(item.items()):
4883 if filter in str(val).lower():
4889 - except MPDError, e:
4890 + except MPDError as e:
4891 raise cherrypy.HTTPError(501, message=str(e))
4892 protocol.exposed = True
4895 return json.dumps(s)
4898 - if mpd.state.get('uptime', '') <> client_uptime:
4899 + if mpd.state.get('uptime', '') != client_uptime:
4900 return json.dumps(mpd.state)
4901 - if mpd.state.get('updating_db', '') <> client_updating_db:
4902 + if mpd.state.get('updating_db', '') != client_updating_db:
4903 return json.dumps(mpd.state)
4906 @@ -649,11 +649,11 @@
4912 - print "Server Ready."
4913 - print "Client175 is available at: http://%s%s:%s" % (shost, sport, SERVER_ROOT)
4918 + print("Server Ready.")
4919 + print("Client175 is available at: http://%s%s:%s" % (shost, sport, SERVER_ROOT))