diff --git a/overviewer.py b/overviewer.py index 8bcebb2..653216d 100755 --- a/overviewer.py +++ b/overviewer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # This file is part of the Minecraft Overviewer. # @@ -21,10 +21,8 @@ import platform import sys # quick version check -if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6): - print("Sorry, the Overviewer requires at least Python 2.6 to run") - if sys.version_info[0] >= 3: - print("and will not run on Python 3.0 or later") +if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 4): + print("Sorry, the Overviewer requires at least Python 3.4 to run.") sys.exit(1) import os @@ -35,6 +33,7 @@ import multiprocessing import time import logging from argparse import ArgumentParser +from collections import OrderedDict from overviewer_core import util from overviewer_core import logger @@ -136,7 +135,7 @@ def main(): # Check for possible shell quoting issues if len(unknowns) > 0: possible_mistakes = [] - for i in xrange(len(unknowns) + 1): + for i in range(len(unknowns) + 1): possible_mistakes.append(" ".join([args.world, args.output] + unknowns[:i])) possible_mistakes.append(" ".join([args.output] + unknowns[:i])) for mistake in possible_mistakes: @@ -183,9 +182,9 @@ def main(): print("Currently running Minecraft Overviewer %s" % util.findGitVersion() + " (%s)" % util.findGitHash()[:7]) try: - import urllib + from urllib import request import json - latest_ver = json.loads(urllib.urlopen("http://overviewer.org/download.json") + latest_ver = json.loads(request.urlopen("http://overviewer.org/download.json") .read())['src'] print("Latest version of Minecraft Overviewer %s (%s)" % (latest_ver['version'], latest_ver['commit'][:7])) @@ -294,7 +293,7 @@ def main(): rendermodes = args.rendermodes.replace("-", "_").split(",") # Now for some good defaults - renders = util.OrderedDict() + renders = OrderedDict() for rm in rendermodes: renders["world-" + rm] = { "world": "world", @@ -337,7 +336,7 @@ def main(): if args.check_terrain: # we are already in the "if configfile" branch logging.info("Looking for a few common texture files...") - for render_name, render in config['renders'].iteritems(): + for render_name, render in config['renders'].items(): logging.info("Looking at render %r.", render_name) # find or create the textures object @@ -356,7 +355,7 @@ def main(): logging.debug("Current log level: {0}.".format(logging.getLogger().level)) def set_renderchecks(checkname, num): - for name, render in config['renders'].iteritems(): + for name, render in config['renders'].items(): if render.get('renderchecks', 0) == 3: logging.warning(checkname + " ignoring render " + repr(name) + " since it's " "marked as \"don't render\".") @@ -381,7 +380,7 @@ def main(): ##################### # Do a few last minute things to each render dictionary here - for rname, render in config['renders'].iteritems(): + for rname, render in config['renders'].items(): # Convert render['world'] to the world path, and store the original # in render['worldname_orig'] try: @@ -437,7 +436,7 @@ def main(): # The changelist support. changelists = {} - for render in config['renders'].itervalues(): + for render in config['renders'].values(): if 'changelist' in render: path = render['changelist'] if path not in changelists: @@ -461,7 +460,7 @@ def main(): # TODO: optionally more caching layers here renders = config['renders'] - for render_name, render in renders.iteritems(): + for render_name, render in renders.items(): logging.debug("Found the following render thing: %r", render) # find or create the world object @@ -572,7 +571,7 @@ def main(): assetMrg.finalize(tilesets) - for out in changelists.itervalues(): + for out in changelists.values(): logging.debug("Closing %s (%s).", out, out.fileno()) out.close() @@ -603,8 +602,8 @@ def list_worlds(): formatString = "%-" + str(worldNameLen) + "s | %-8s | %-16s | %s " print(formatString % ("World", "Playtime", "Modified", "Path")) print(formatString % ("-" * worldNameLen, "-" * 8, '-' * 16, '-' * 4)) - for name, info in sorted(worlds.iteritems()): - if isinstance(name, basestring) and name.startswith("World") and len(name) == 6: + for name, info in sorted(worlds.items()): + if isinstance(name, str) and name.startswith("World") and len(name) == 6: try: world_n = int(name[-1]) # we'll catch this one later, when it shows up as an diff --git a/overviewer_core/__init__.py b/overviewer_core/__init__.py index ba12f33..3a2a491 100644 --- a/overviewer_core/__init__.py +++ b/overviewer_core/__init__.py @@ -2,13 +2,15 @@ # Code to check to make sure c_overviewer is built and working # +from __future__ import print_function + import os.path import os import platform import traceback import sys -import util +from . import util def check_c_overviewer(): """Check to make sure c_overviewer works and is up-to-date. Prints @@ -18,29 +20,28 @@ def check_c_overviewer(): root_dir = util.get_program_path() # make sure the c_overviewer extension is available try: - import c_overviewer + from . import c_overviewer except ImportError: if os.environ.get("OVERVIEWER_DEBUG_IMPORT") == "1": traceback.print_exc() ## if this is a frozen windows package, the following error messages about ## building the c_overviewer extension are not appropriate if hasattr(sys, "frozen") and platform.system() == 'Windows': - print "Something has gone wrong importing the c_overviewer extension. Please" - print "make sure the 2008 and 2010 redistributable packages from Microsoft" - print "are installed." + print("Something has gone wrong importing the c_overviewer extension. Please make sure " + "the 2008 and 2010 redistributable packages from Microsoft are installed.") return 1 ## try to find the build extension ext = os.path.join(root_dir, "overviewer_core", "c_overviewer.%s" % ("pyd" if platform.system() == "Windows" else "so")) if os.path.exists(ext): traceback.print_exc() - print "" - print "Something has gone wrong importing the c_overviewer extension. Please" - print "make sure it is up-to-date (clean and rebuild)" + print() + print("Something has gone wrong importing the c_overviewer extension. Please make sure " + "it is up-to-date. (clean and rebuild)") return 1 - print "You need to compile the c_overviewer module to run Minecraft Overviewer." - print "Run `python setup.py build`, or see the README for details." + print("You need to compile the c_overviewer module to run Minecraft Overviewer.") + print("Run `python setup.py build`, or see the README for details.") return 1 # @@ -54,14 +55,15 @@ def check_c_overviewer(): if os.path.exists(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")): with open(os.path.join(root_dir, "overviewer_core", "src", "overviewer.h")) as f: lines = f.readlines() - lines = filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), lines) + lines = list(filter(lambda x: x.startswith("#define OVERVIEWER_EXTENSION_VERSION"), + lines)) if lines: l = lines[0] if int(l.split()[2].strip()) != c_overviewer.extension_version(): - print "Please rebuild your c_overviewer module. It is out of date!" + print("Please rebuild your c_overviewer module. It is out of date!") return 1 else: - print "Please rebuild your c_overviewer module. It is out of date!" + print("Please rebuild your c_overviewer module. It is out of date!") return 1 # all good! diff --git a/overviewer_core/assetmanager.py b/overviewer_core/assetmanager.py index a0a4b82..26ba9c3 100644 --- a/overviewer_core/assetmanager.py +++ b/overviewer_core/assetmanager.py @@ -23,9 +23,9 @@ import traceback from PIL import Image -import world -import util -from files import FileReplacer, mirror_dir, get_fs_caps +from . import world +from . import util +from .files import FileReplacer, mirror_dir, get_fs_caps class AssetManager(object): @@ -53,7 +53,7 @@ top-level directory. with open(config_loc) as c: ovconf_str = "{" + "\n".join(c.readlines()[1:-1]) + "}" self.overviewerConfig = json.loads(ovconf_str) - except Exception, e: + except Exception as e: if os.path.exists(config_loc): logging.warning("A previous overviewerConfig.js was found, " "but I couldn't read it for some reason." @@ -61,16 +61,6 @@ top-level directory. logging.debug(traceback.format_exc()) self.overviewerConfig = dict(tilesets=dict()) - # Make sure python knows the preferred encoding. If it does not, set it - # to utf-8" - self.preferredencoding = locale.getpreferredencoding() - try: - # We don't care what is returned, just that we can get a codec. - codecs.lookup(self.preferredencoding) - except LookupError: - self.preferredencoding = "utf_8" - logging.debug("Preferred enoding set to: %s", self.preferredencoding) - def get_tileset_config(self, name): "Return the correct dictionary from the parsed overviewerConfig.js" for conf in self.overviewerConfig['tilesets']: @@ -213,10 +203,7 @@ top-level directory. index = codecs.open(indexpath, 'r', encoding='UTF-8').read() index = index.replace("{title}", "Minecraft Overviewer") - index = index.replace("{time}", - time.strftime("%a, %d %b %Y %H:%M:%S %Z", - time.localtime()) - .decode(self.preferredencoding)) + index = index.replace("{time}", time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime())) versionstr = "%s (%s)" % (util.findGitVersion(), util.findGitHash()[:7]) index = index.replace("{version}", versionstr) diff --git a/overviewer_core/configParser.py b/overviewer_core/configParser.py index cad7c75..e312d77 100644 --- a/overviewer_core/configParser.py +++ b/overviewer_core/configParser.py @@ -4,8 +4,8 @@ import os.path import logging import traceback -import settingsDefinition -import settingsValidators +from . import settingsDefinition +from . import settingsValidators class MissingConfigException(Exception): "To be thrown when the config file can't be found" @@ -76,12 +76,14 @@ class MultiWorldParser(object): # The global environment should be the rendermode module, so the config # file has access to those resources. - import rendermodes + from . import rendermodes try: - execfile(settings_file, rendermodes.__dict__, self._config_state) + with open(settings_file, "rb") as settings_file_handle: + exec(compile(settings_file_handle.read(), settings_file, 'exec'), + rendermodes.__dict__, self._config_state) - except Exception, ex: + except Exception as ex: if isinstance(ex, SyntaxError): logging.error("Syntax error parsing %s" % settings_file) logging.error("The traceback below will tell you which line triggered the syntax error\n") @@ -109,7 +111,7 @@ class MultiWorldParser(object): # At this point, make a pass through the file to possibly set global # render defaults render_settings = self._settings['renders'].validator.valuevalidator.config - for key in self._config_state.iterkeys(): + for key in self._config_state.keys(): if key not in self._settings: if key in render_settings: setting = render_settings[key] diff --git a/overviewer_core/dispatcher.py b/overviewer_core/dispatcher.py index a56f7f5..a5c3846 100644 --- a/overviewer_core/dispatcher.py +++ b/overviewer_core/dispatcher.py @@ -13,12 +13,12 @@ # You should have received a copy of the GNU General Public License along # with the Overviewer. If not, see . -import util +from . import util import multiprocessing import multiprocessing.managers -import Queue +import queue import time -from signals import Signal +from .signals import Signal class Dispatcher(object): """This class coordinates the work of all the TileSet objects @@ -51,7 +51,7 @@ class Dispatcher(object): # iterate through all possible phases num_phases = [tileset.get_num_phases() for tileset in tilesetlist] - for phase in xrange(max(num_phases)): + for phase in range(max(num_phases)): # construct a list of iterators to use for this phase work_iterators = [] for i, tileset in enumerate(tilesetlist): @@ -235,7 +235,7 @@ class MultiprocessingDispatcherProcess(multiprocessing.Process): def handler(*args, **kwargs): self.signal_queue.put((name, args, kwargs), False) sig.set_interceptor(handler) - for name, sig in Signal.signals.iteritems(): + for name, sig in Signal.signals.items(): register_signal(name, sig) # notify that we're starting up @@ -259,7 +259,7 @@ class MultiprocessingDispatcherProcess(multiprocessing.Process): ret = self.tilesets[ti].do_work(workitem) result = (ti, workitem, ret,) self.result_queue.put(result, False) - except Queue.Empty: + except queue.Empty: pass class MultiprocessingDispatcher(Dispatcher): @@ -288,7 +288,7 @@ class MultiprocessingDispatcher(Dispatcher): # create and fill the pool self.pool = [] - for i in xrange(self.local_procs): + for i in range(self.local_procs): proc = MultiprocessingDispatcherProcess(self.manager) proc.start() self.pool.append(proc) @@ -300,7 +300,7 @@ class MultiprocessingDispatcher(Dispatcher): self._handle_messages() # send of the end-of-jobs sentinel - for p in xrange(self.num_workers): + for p in range(self.num_workers): self.job_queue.put(None, False) # TODO better way to be sure worker processes get the message @@ -350,7 +350,7 @@ class MultiprocessingDispatcher(Dispatcher): else: # new worker self.num_workers += 1 - except Queue.Empty: + except queue.Empty: result_empty = True if not signal_empty: try: @@ -363,7 +363,7 @@ class MultiprocessingDispatcher(Dispatcher): sig = Signal.signals[name] sig.emit_intercepted(*args, **kwargs) - except Queue.Empty: + except queue.Empty: signal_empty = True return finished_jobs diff --git a/overviewer_core/files.py b/overviewer_core/files.py index 15647fe..0d372c6 100644 --- a/overviewer_core/files.py +++ b/overviewer_core/files.py @@ -144,7 +144,7 @@ class FileReplacer(object): # error try: os.remove(self.tmpname) - except Exception, e: + except Exception as e: logging.warning("An error was raised, so I was doing " "some cleanup first, but I couldn't remove " "'%s'!", self.tmpname) @@ -153,7 +153,7 @@ class FileReplacer(object): if self.caps.get("chmod_works") and os.path.exists(self.destname): try: shutil.copymode(self.destname, self.tmpname) - except OSError, e: + except OSError as e: # Ignore errno ENOENT: file does not exist. Due to a race # condition, two processes could conceivably try and update # the same temp file at the same time @@ -162,7 +162,7 @@ class FileReplacer(object): # atomic rename into place try: os.rename(self.tmpname, self.destname) - except OSError, e: + except OSError as e: # Ignore errno ENOENT: file does not exist. Due to a race # condition, two processes could conceivably try and update # the same temp file at the same time diff --git a/overviewer_core/logger.py b/overviewer_core/logger.py index f46827e..0514b0c 100644 --- a/overviewer_core/logger.py +++ b/overviewer_core/logger.py @@ -18,7 +18,7 @@ import logging import os import platform import sys -from cStringIO import StringIO +from io import BytesIO # Some cool code for colored logging: # For background, add 40. For foreground, add 30 @@ -88,7 +88,7 @@ class WindowsOutputStream(object): def write(self, s): - msg_strm = StringIO(s) + msg_strm = BytesIO(s) while (True): c = msg_strm.read(1) diff --git a/overviewer_core/nbt.py b/overviewer_core/nbt.py index fa494ab..cefdaf1 100644 --- a/overviewer_core/nbt.py +++ b/overviewer_core/nbt.py @@ -15,7 +15,7 @@ import functools import gzip -import StringIO +from io import BytesIO import struct import zlib @@ -25,7 +25,7 @@ import zlib def _file_loader(func): @functools.wraps(func) def wrapper(fileobj, *args): - if isinstance(fileobj, basestring): + if type(fileobj) == str: # Is actually a filename fileobj = open(fileobj, 'rb', 4096) return func(fileobj, *args) @@ -92,7 +92,7 @@ class NBTFileReader(object): # pure zlib stream -- maybe later replace this with # a custom zlib file object? data = zlib.decompress(fileobj.read()) - self._file = StringIO.StringIO(data) + self._file = BytesIO(data) # mapping of NBT type ids to functions to read them out self._read_tagmap = { @@ -168,7 +168,7 @@ class NBTFileReader(object): read_method = self._read_tagmap[tagid] l = [] - for _ in xrange(length): + for _ in range(length): l.append(read_method()) return l @@ -203,7 +203,7 @@ class NBTFileReader(object): name = self._read_tag_string() payload = self._read_tag_compound() return (name, payload) - except (struct.error, ValueError, TypeError), e: + except (struct.error, ValueError, TypeError) as e: raise CorruptNBTError("could not parse nbt: %s" % (str(e),)) @@ -252,9 +252,9 @@ class MCRFileReader(object): file, as (x, z) coordinate tuples. To load these chunks, provide these coordinates to load_chunk().""" - for x in xrange(32): - for z in xrange(32): - if self._locations[x + z * 32] >> 8 != 0: + for x in range(32): + for z in range(32): + if self._locations[int(x + z * 32)] >> 8 != 0: yield (x, z) def get_chunk_timestamp(self, x, z): @@ -264,13 +264,13 @@ class MCRFileReader(object): """ x = x % 32 z = z % 32 - return self._timestamps[x + z * 32] + return self._timestamps[int(x + z * 32)] def chunk_exists(self, x, z): """Determines if a chunk exists.""" x = x % 32 z = z % 32 - return self._locations[x + z * 32] >> 8 != 0 + return self._locations[int(x + z * 32)] >> 8 != 0 def load_chunk(self, x, z): """Return a (name, data) tuple for the given chunk, or @@ -281,7 +281,7 @@ class MCRFileReader(object): have the chunks load out of regions properly.""" x = x % 32 z = z % 32 - location = self._locations[x + z * 32] + location = self._locations[int(x + z * 32)] offset = (location >> 8) * 4096 sectors = location & 0xff @@ -311,16 +311,16 @@ class MCRFileReader(object): raise CorruptRegionError("unsupported chunk compression type: %i " "(should be 1 or 2)" % (compression,)) - # turn the rest of the data into a StringIO object + # turn the rest of the data into a BytesIO object # (using data_length - 1, as we already read 1 byte for compression) data = self._file.read(data_length - 1) if len(data) != data_length - 1: raise CorruptRegionError("chunk length is invalid") - data = StringIO.StringIO(data) + data = BytesIO(data) try: return NBTFileReader(data, is_gzip=is_gzip).read_all() except CorruptionError: raise - except Exception, e: + except Exception as e: raise CorruptChunkError("Misc error parsing chunk: " + str(e)) diff --git a/overviewer_core/observer.py b/overviewer_core/observer.py index 0ebc4ad..267c29b 100644 --- a/overviewer_core/observer.py +++ b/overviewer_core/observer.py @@ -19,8 +19,8 @@ import os import sys import time -import progressbar -import rcon +from . import progressbar +from . import rcon class Observer(object): diff --git a/overviewer_core/optimizeimages.py b/overviewer_core/optimizeimages.py index bb0d28c..aaa8280 100644 --- a/overviewer_core/optimizeimages.py +++ b/overviewer_core/optimizeimages.py @@ -34,8 +34,7 @@ class Optimizer: path = os.environ.get("PATH").split(os.pathsep) def exists_in_path(prog): - result = filter(lambda x: os.path.exists(os.path.join(x, prog)), - path) + result = [x for x in path if os.path.exists(os.path.join(x, prog))] return len(result) != 0 binaries = self.binarynames + [x + ".exe" for x in self.binarynames] diff --git a/overviewer_core/progressbar.py b/overviewer_core/progressbar.py index 9b743d0..4e0305c 100644 --- a/overviewer_core/progressbar.py +++ b/overviewer_core/progressbar.py @@ -189,13 +189,13 @@ class Bar(ProgressBarWidgetHFill): self.left = left self.right = right def _format_marker(self, pbar): - if isinstance(self.marker, (str, unicode)): + if isinstance(self.marker, str): return self.marker else: return self.marker.update(pbar) def update(self, pbar, width): percent = pbar.percentage() - cwidth = width - len(self.left) - len(self.right) + cwidth = int(width - len(self.left) - len(self.right)) marked_width = int(percent * cwidth / 100) m = self._format_marker(pbar) bar = (self.left + (m*marked_width).ljust(cwidth) + self.right) @@ -283,7 +283,7 @@ class ProgressBar(object): r.append(w) hfill_inds.append(i) num_hfill += 1 - elif isinstance(w, (str, unicode)): + elif isinstance(w, str): r.append(w) currwidth += len(w) else: diff --git a/overviewer_core/rendermodes.py b/overviewer_core/rendermodes.py index 00cac4a..7ae67fe 100644 --- a/overviewer_core/rendermodes.py +++ b/overviewer_core/rendermodes.py @@ -14,7 +14,7 @@ # with the Overviewer. If not, see . from PIL import Image -import textures +from . import textures """The contents of this file are imported into the namespace of config files. It also defines the render primitive objects, which are used by the C code. @@ -31,13 +31,13 @@ class RenderPrimitive(object): raise RuntimeError("RenderPrimitive cannot be used directly") self.option_values = {} - for key, val in kwargs.iteritems(): + for key, val in kwargs.items(): if not key in self.options: raise ValueError("primitive `{0}' has no option `{1}'".format(self.name, key)) self.option_values[key] = val # set up defaults - for name, (description, default) in self.options.iteritems(): + for name, (description, default) in self.options.items(): if not name in self.option_values: self.option_values[name] = default diff --git a/overviewer_core/settingsDefinition.py b/overviewer_core/settingsDefinition.py index 8e62f98..416a1c0 100644 --- a/overviewer_core/settingsDefinition.py +++ b/overviewer_core/settingsDefinition.py @@ -43,10 +43,11 @@ # available during the execution of the config file. This way, container types # can be initialized and then appended/added to when the config file is parsed. -from settingsValidators import * -import util -from observer import ProgressBarObserver, LoggingObserver, JSObserver -from optimizeimages import pngnq, optipng, pngcrush +from collections import OrderedDict + +from .settingsValidators import * +from .observer import ProgressBarObserver, LoggingObserver, JSObserver +from .optimizeimages import pngnq, optipng, pngcrush import platform import sys @@ -60,7 +61,7 @@ import sys # objects with their respective validators. # config file. -renders = Setting(required=True, default=util.OrderedDict(), +renders = Setting(required=True, default=OrderedDict(), validator=make_dictValidator(validateStr, make_configDictValidator( { "world": Setting(required=True, validator=validateStr, default=None), @@ -99,7 +100,7 @@ renders = Setting(required=True, default=util.OrderedDict(), ))) # The worlds dict, mapping world names to world paths -worlds = Setting(required=True, validator=make_dictValidator(validateStr, validateWorldPath), default=util.OrderedDict()) +worlds = Setting(required=True, validator=make_dictValidator(validateStr, validateWorldPath), default=OrderedDict()) outputdir = Setting(required=True, validator=validateOutputDir, default=None) diff --git a/overviewer_core/settingsValidators.py b/overviewer_core/settingsValidators.py index 8241473..41a29c3 100644 --- a/overviewer_core/settingsValidators.py +++ b/overviewer_core/settingsValidators.py @@ -2,11 +2,12 @@ import logging import os import os.path +from collections import OrderedDict -import rendermodes -import util -from optimizeimages import Optimizer -from world import LOWER_LEFT, LOWER_RIGHT, UPPER_LEFT, UPPER_RIGHT +from . import rendermodes +from . import util +from .optimizeimages import Optimizer +from .world import LOWER_LEFT, LOWER_RIGHT, UPPER_LEFT, UPPER_RIGHT class ValidationException(Exception): @@ -179,8 +180,8 @@ def validateBGColor(color): def validateOptImg(optimizers): - if isinstance(optimizers, (int, long)): - from optimizeimages import pngcrush + if isinstance(optimizers, int): + from .optimizeimages import pngcrush logging.warning("You're using a deprecated definition of optimizeimg. " "We'll do what you say for now, but please fix this as soon as possible.") optimizers = [pngcrush()] @@ -189,7 +190,7 @@ def validateOptImg(optimizers): "Make sure you specify them like [foo()], with square brackets.") if optimizers: - for opt, next_opt in zip(optimizers, optimizers[1:]) + [(optimizers[-1], None)]: + for opt, next_opt in list(zip(optimizers, optimizers[1:])) + [(optimizers[-1], None)]: if not isinstance(opt, Optimizer): raise ValidationException("Invalid Optimizer!") @@ -272,7 +273,7 @@ def validateCrop(value): def validateObserver(observer): - if all(map(lambda m: hasattr(observer, m), ['start', 'add', 'update', 'finish'])): + if all([hasattr(observer, m) for m in ['start', 'add', 'update', 'finish']]): return observer else: raise ValidationException("%r does not look like an observer." % repr(observer)) @@ -316,8 +317,8 @@ def make_dictValidator(keyvalidator, valuevalidator): """ def v(d): - newd = util.OrderedDict() - for key, value in d.iteritems(): + newd = OrderedDict() + for key, value in d.items(): newd[keyvalidator(key)] = valuevalidator(value) return newd # Put these objects as attributes of the function so they can be accessed @@ -345,7 +346,7 @@ def make_configDictValidator(config, ignore_undefined=False): """ def configDictValidator(d): - newdict = util.OrderedDict() + newdict = OrderedDict() # values are config keys that the user specified that don't match any # valid key @@ -353,10 +354,10 @@ def make_configDictValidator(config, ignore_undefined=False): undefined_key_matches = {} # Go through the keys the user gave us and make sure they're all valid. - for key in d.iterkeys(): + for key in d.keys(): if key not in config: # Try to find a probable match - match = _get_closest_match(key, config.iterkeys()) + match = _get_closest_match(key, iter(config.keys())) if match and ignore_undefined: # Save this for later. It only matters if this is a typo of # some required key that wasn't specified. (If all required @@ -377,7 +378,7 @@ def make_configDictValidator(config, ignore_undefined=False): # Iterate through the defined keys in the configuration (`config`), # checking each one to see if the user specified it (in `d`). Then # validate it and copy the result to `newdict` - for configkey, configsetting in config.iteritems(): + for configkey, configsetting in config.items(): if configkey in d: # This key /was/ specified in the user's dict. Make sure it validates. newdict[configkey] = configsetting.validator(d[configkey]) @@ -414,9 +415,9 @@ def _levenshtein(s1, s2): l1 = len(s1) l2 = len(s2) - matrix = [range(l1 + 1)] * (l2 + 1) + matrix = [list(range(l1 + 1))] * (l2 + 1) for zz in range(l2 + 1): - matrix[zz] = range(zz, zz + l1 + 1) + matrix[zz] = list(range(zz, zz + l1 + 1)) for zz in range(0, l2): for sz in range(0, l1): if s1[sz] == s2[zz]: diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 5c9c51b..d25cd3c 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -40,7 +40,6 @@ PyObject *init_chunk_render(void) { if (textures) { Py_RETURN_NONE; } - textures = PyImport_ImportModule("overviewer_core.textures"); /* ensure none of these pointers are NULL */ if ((!textures)) { @@ -50,13 +49,13 @@ PyObject *init_chunk_render(void) { tmp = PyObject_GetAttrString(textures, "max_blockid"); if (!tmp) return NULL; - max_blockid = PyInt_AsLong(tmp); + max_blockid = PyLong_AsLong(tmp); Py_DECREF(tmp); tmp = PyObject_GetAttrString(textures, "max_data"); if (!tmp) return NULL; - max_data = PyInt_AsLong(tmp); + max_data = PyLong_AsLong(tmp); Py_DECREF(tmp); /* assemble the property table */ @@ -81,7 +80,7 @@ PyObject *init_chunk_render(void) { block_properties = calloc(max_blockid, sizeof(unsigned char)); for (i = 0; i < max_blockid; i++) { - PyObject *block = PyInt_FromLong(i); + PyObject *block = PyLong_FromLong(i); if (PySequence_Contains(known_blocks, block)) block_properties[i] |= 1 << KNOWN; @@ -177,7 +176,7 @@ int load_chunk(RenderState* state, int x, int z, unsigned char required) { if (!ycoord) continue; - sectiony = PyInt_AsLong(ycoord); + sectiony = PyLong_AsLong(ycoord); if (sectiony >= 0 && sectiony < SECTIONS_PER_CHUNK) load_chunk_section(dest, sectiony, section); } @@ -487,7 +486,7 @@ generate_pseudo_data(RenderState *state, unsigned short ancilData) { PyObject *texrot; int northdir; texrot = PyObject_GetAttrString(state->textures, "rotation"); - northdir = PyInt_AsLong(texrot); + northdir = PyLong_AsLong(texrot); /* fix the rotation value for different northdirections */ #define FIX_ROT(x) (((x) & ~0x3) | repair_rot[((x) & 0x3) | (northdir << 2)]) @@ -617,8 +616,8 @@ chunk_render(PyObject *self, PyObject *args) { imgsize1_py = PySequence_GetItem(imgsize, 1); Py_DECREF(imgsize); - imgsize0 = PyInt_AsLong(imgsize0_py); - imgsize1 = PyInt_AsLong(imgsize1_py); + imgsize0 = PyLong_AsLong(imgsize0_py); + imgsize1 = PyLong_AsLong(imgsize1_py); Py_DECREF(imgsize0_py); Py_DECREF(imgsize1_py); diff --git a/overviewer_core/src/main.c b/overviewer_core/src/main.c index e3eee9c..9e1e82a 100644 --- a/overviewer_core/src/main.c +++ b/overviewer_core/src/main.c @@ -38,12 +38,20 @@ static PyMethodDef COverviewerMethods[] = { {NULL, NULL, 0, NULL} /* Sentinel */ }; +static PyModuleDef COverviewerModule = { + PyModuleDef_HEAD_INIT, + "c_overviewer", + "", // TODO: Add documentation here. + -1, + COverviewerMethods +}; + PyMODINIT_FUNC -initc_overviewer(void) +PyInit_c_overviewer(void) { PyObject *mod, *numpy; - mod = Py_InitModule("c_overviewer", COverviewerMethods); + mod = PyModule_Create(&COverviewerModule); /* for numpy normally you should use import_array(), but that will break across @@ -57,8 +65,9 @@ initc_overviewer(void) if (!init_chunk_render()) { PyErr_Print(); exit(1); - return; + return NULL; } init_endian(); + return mod; } diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h index ca29186..5f8001b 100644 --- a/overviewer_core/src/overviewer.h +++ b/overviewer_core/src/overviewer.h @@ -33,7 +33,7 @@ // increment this value if you've made a change to the c extesion // and want to force users to rebuild -#define OVERVIEWER_EXTENSION_VERSION 56 +#define OVERVIEWER_EXTENSION_VERSION 57 /* Python PIL, and numpy headers */ #include diff --git a/overviewer_core/src/primitives/base.c b/overviewer_core/src/primitives/base.c index 3a955e2..7e24d0f 100644 --- a/overviewer_core/src/primitives/base.c +++ b/overviewer_core/src/primitives/base.c @@ -234,9 +234,9 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec /* look up color! */ color = PySequence_GetItem(color_table, tabley * 256 + tablex); - r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); - g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); - b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); + r = PyLong_AsLong(PyTuple_GET_ITEM(color, 0)); + g = PyLong_AsLong(PyTuple_GET_ITEM(color, 1)); + b = PyLong_AsLong(PyTuple_GET_ITEM(color, 2)); Py_DECREF(color); /* do the after-coloration */ diff --git a/overviewer_core/src/primitives/depth-tinting.c b/overviewer_core/src/primitives/depth-tinting.c index 99d068a..8a28f76 100644 --- a/overviewer_core/src/primitives/depth-tinting.c +++ b/overviewer_core/src/primitives/depth-tinting.c @@ -56,9 +56,9 @@ depth_tinting_draw(void *data, RenderState *state, PyObject *src, PyObject *mask y = (y * 128) / (16 * SECTIONS_PER_CHUNK); /* get the colors and tint and tint */ - r = PyInt_AsLong(PyList_GetItem(self->depth_colors, 0 + y*3)); - g = PyInt_AsLong(PyList_GetItem(self->depth_colors, 1 + y*3)); - b = PyInt_AsLong(PyList_GetItem(self->depth_colors, 2 + y*3)); + r = PyLong_AsLong(PyList_GetItem(self->depth_colors, 0 + y*3)); + g = PyLong_AsLong(PyList_GetItem(self->depth_colors, 1 + y*3)); + b = PyLong_AsLong(PyList_GetItem(self->depth_colors, 2 + y*3)); tint_with_mask(state->img, r, g, b, 255, mask, state->imgx, state->imgy, 0, 0); } diff --git a/overviewer_core/src/primitives/hide.c b/overviewer_core/src/primitives/hide.c index cdb24e8..6f06c8b 100644 --- a/overviewer_core/src/primitives/hide.c +++ b/overviewer_core/src/primitives/hide.c @@ -52,9 +52,9 @@ hide_start(void *data, RenderState *state, PyObject *support) { for (i = 0; i < blocks_size; i++) { PyObject *block = PyList_GET_ITEM(opt, i); - if (PyInt_Check(block)) { + if (PyLong_Check(block)) { /* format 1: just a block id */ - self->rules[i].blockid = PyInt_AsLong(block); + self->rules[i].blockid = PyLong_AsLong(block); self->rules[i].has_data = 0; } else if (PyArg_ParseTuple(block, "Hb", &(self->rules[i].blockid), &(self->rules[i].data))) { /* format 2: (blockid, data) */ diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index 97f7f0a..40257a2 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -45,9 +45,9 @@ calculate_light_color_fancy(void *data, index = skylight + blocklight * 16; color = PySequence_GetItem(mode->lightcolor, index); - *r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); - *g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); - *b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); + *r = PyLong_AsLong(PyTuple_GET_ITEM(color, 0)); + *g = PyLong_AsLong(PyTuple_GET_ITEM(color, 1)); + *b = PyLong_AsLong(PyTuple_GET_ITEM(color, 2)); Py_DECREF(color); } @@ -78,9 +78,9 @@ calculate_light_color_fancy_night(void *data, index = skylight + blocklight * 16; color = PySequence_GetItem(mode->lightcolor, index); - *r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0)); - *g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1)); - *b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2)); + *r = PyLong_AsLong(PyTuple_GET_ITEM(color, 0)); + *g = PyLong_AsLong(PyTuple_GET_ITEM(color, 1)); + *b = PyLong_AsLong(PyTuple_GET_ITEM(color, 2)); Py_DECREF(color); } diff --git a/overviewer_core/src/rendermodes.c b/overviewer_core/src/rendermodes.c index 6ff99de..90a748f 100644 --- a/overviewer_core/src/rendermodes.c +++ b/overviewer_core/src/rendermodes.c @@ -40,7 +40,7 @@ RenderPrimitive *render_primitive_create(PyObject *prim, RenderState *state) { pyname = PyObject_GetAttrString(prim, "name"); if (!pyname) return NULL; - name = PyString_AsString(pyname); + name = PyUnicode_AsUTF8(pyname); for (i = 0; render_primitives[i] != NULL; i++) { if (strcmp(render_primitives[i]->name, name) == 0) { @@ -204,11 +204,10 @@ int render_mode_parse_option(PyObject *support, const char *name, const char *fo Py_DECREF(dict); if (!ret) { - PyObject *errtype, *errvalue, *errtraceback; - const char *errstring; + PyObject *errtype, *errvalue, *errtraceback, *errstring; PyErr_Fetch(&errtype, &errvalue, &errtraceback); - errstring = PyString_AsString(errvalue); + errstring = PyUnicode_AsUTF8String(errvalue); PyErr_Format(PyExc_TypeError, "rendermode option \"%s\" has incorrect type (%s)", name, errstring); diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index b2485d0..01a04eb 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -18,7 +18,7 @@ import imp import os import os.path import zipfile -from cStringIO import StringIO +from io import BytesIO import math from random import randint import numpy @@ -26,8 +26,32 @@ from PIL import Image, ImageEnhance, ImageOps, ImageDraw import logging import functools -import util -from c_overviewer import alpha_over +from . import util + + +# global variables to collate information in @material decorators +blockmap_generators = {} + +known_blocks = set() +used_datas = set() +max_blockid = 0 +max_data = 0 + +transparent_blocks = set() +solid_blocks = set() +fluid_blocks = set() +nospawn_blocks = set() +nodata_blocks = set() + + +# This is here for circular import reasons. +# Please don't ask, I choose to repress these memories. +# ... okay fine I'll tell you. +# Initialising the C extension requires access to the globals above. +# Due to the circular import, this wouldn't work, unless we reload the +# module in the C extension or just move the import below its dependencies. +from .c_overviewer import alpha_over + class TextureException(Exception): "To be thrown when a texture is not found." @@ -37,6 +61,7 @@ class TextureException(Exception): color_map = ["white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"] + ## ## Textures object ## @@ -76,10 +101,11 @@ class Textures(object): del attributes[attr] except KeyError: pass + attributes['jar'] = None return attributes def __setstate__(self, attrs): # regenerate textures, if needed - for attr, val in attrs.iteritems(): + for attr, val in list(attrs.items()): setattr(self, attr, val) self.texture_cache = {} if self.generated: @@ -99,7 +125,7 @@ class Textures(object): global known_blocks, used_datas self.blockmap = [None] * max_blockid * max_data - for (blockid, data), texgen in blockmap_generators.iteritems(): + for (blockid, data), texgen in list(blockmap_generators.items()): tex = texgen(self, blockid, data) self.blockmap[blockid * max_data + data] = self.generate_texture_tuple(tex) @@ -224,7 +250,7 @@ class Textures(object): self.jar.getinfo(jarfilename) if verbose: logging.info("Found (cached) %s in '%s'", jarfilename, self.jarpath) return self.jar.open(jarfilename) - except (KeyError, IOError), e: + except (KeyError, IOError) as e: pass # Find an installed minecraft client jar and look in it for the texture @@ -285,7 +311,7 @@ class Textures(object): if verbose: logging.info("Found %s in '%s'", jarfilename, jarpath) self.jar, self.jarpath = jar, jarpath return jar.open(jarfilename) - except (KeyError, IOError), e: + except (KeyError, IOError) as e: pass if verbose: logging.info("Did not find file {0} in jar {1}".format(filename, jarpath)) @@ -334,7 +360,7 @@ class Textures(object): return self.texture_cache[filename] fileobj = self.find_file(filename) - buffer = StringIO(fileobj.read()) + buffer = BytesIO(fileobj.read()) img = Image.open(buffer).convert("RGBA") self.texture_cache[filename] = img return img @@ -444,8 +470,8 @@ class Textures(object): textures = [] (terrain_width, terrain_height) = terrain.size texture_resolution = terrain_width / 16 - for y in xrange(16): - for x in xrange(16): + for y in range(16): + for x in range(16): left = x*texture_resolution upper = y*texture_resolution right = left+texture_resolution @@ -815,19 +841,6 @@ class Textures(object): ## The other big one: @material and associated framework ## -# global variables to collate information in @material decorators -blockmap_generators = {} - -known_blocks = set() -used_datas = set() -max_blockid = 0 -max_data = 0 - -transparent_blocks = set() -solid_blocks = set() -fluid_blocks = set() -nospawn_blocks = set() -nodata_blocks = set() # the material registration decorator def material(blockid=[], data=[0], **kwargs): @@ -837,11 +850,11 @@ def material(blockid=[], data=[0], **kwargs): # make sure blockid and data are iterable try: iter(blockid) - except: + except Exception: blockid = [blockid,] try: iter(data) - except: + except Exception: data = [data,] def inner_material(func): @@ -924,7 +937,7 @@ def billboard(blockid=[], imagename=None, **kwargs): ## # stone -@material(blockid=1, data=range(7), solid=True) +@material(blockid=1, data=list(range(7)), solid=True) def stone(self, blockid, data): if data == 0: # regular old-school stone img = self.load_image_texture("assets/minecraft/textures/block/stone.png") @@ -942,7 +955,7 @@ def stone(self, blockid, data): img = self.load_image_texture("assets/minecraft/textures/block/polished_andesite.png") return self.build_block(img, img) -@material(blockid=2, data=range(11)+[0x10,], solid=True) +@material(blockid=2, data=list(range(11))+[0x10,], solid=True) def grass(self, blockid, data): # 0x10 bit means SNOW side_img = self.load_image_texture("assets/minecraft/textures/block/grass_block_side.png") @@ -954,7 +967,7 @@ def grass(self, blockid, data): return img # dirt -@material(blockid=3, data=range(3), solid=True) +@material(blockid=3, data=list(range(3)), solid=True) def dirt_blocks(self, blockid, data): side_img = self.load_image_texture("assets/minecraft/textures/block/dirt.png") if data == 0: # normal @@ -970,7 +983,7 @@ def dirt_blocks(self, blockid, data): block(blockid=4, top_image="assets/minecraft/textures/block/cobblestone.png") # wooden planks -@material(blockid=5, data=range(6), solid=True) +@material(blockid=5, data=list(range(6)), solid=True) def wooden_planks(self, blockid, data): if data == 0: # normal return self.build_block(self.load_image_texture("assets/minecraft/textures/block/oak_planks.png"), self.load_image_texture("assets/minecraft/textures/block/oak_planks.png")) @@ -985,7 +998,7 @@ def wooden_planks(self, blockid, data): if data == 5: # dark oak return self.build_block(self.load_image_texture("assets/minecraft/textures/block/dark_oak_planks.png"),self.load_image_texture("assets/minecraft/textures/block/dark_oak_planks.png")) -@material(blockid=6, data=range(16), transparent=True) +@material(blockid=6, data=list(range(16)), transparent=True) def saplings(self, blockid, data): # usual saplings tex = self.load_image_texture("assets/minecraft/textures/block/oak_sapling.png") @@ -1007,7 +1020,7 @@ block(blockid=7, top_image="assets/minecraft/textures/block/bedrock.png") # water, glass, and ice (no inner surfaces) # uses pseudo-ancildata found in iterate.c -@material(blockid=[8, 9, 20, 79, 95], data=range(512), fluid=(8, 9), transparent=True, nospawn=True, solid=(79, 20, 95)) +@material(blockid=[8, 9, 20, 79, 95], data=list(range(512)), fluid=(8, 9), transparent=True, nospawn=True, solid=(79, 20, 95)) def no_inner_surfaces(self, blockid, data): if blockid == 8 or blockid == 9: texture = self.load_water() @@ -1054,13 +1067,13 @@ def no_inner_surfaces(self, blockid, data): img = self.build_full_block(top,None,None,side3,side4) return img -@material(blockid=[10, 11], data=range(16), fluid=True, transparent=False, nospawn=True) +@material(blockid=[10, 11], data=list(range(16)), fluid=True, transparent=False, nospawn=True) def lava(self, blockid, data): lavatex = self.load_lava() return self.build_block(lavatex, lavatex) # sand -@material(blockid=12, data=range(2), solid=True) +@material(blockid=12, data=list(range(2)), solid=True) def sand_blocks(self, blockid, data): if data == 0: # normal img = self.build_block(self.load_image_texture("assets/minecraft/textures/block/sand.png"), self.load_image_texture("assets/minecraft/textures/block/sand.png")) @@ -1077,7 +1090,7 @@ block(blockid=15, top_image="assets/minecraft/textures/block/iron_ore.png") # coal ore block(blockid=16, top_image="assets/minecraft/textures/block/coal_ore.png") -@material(blockid=[17,162,11306,11307,11308,11309,11310,11311], data=range(12), solid=True) +@material(blockid=[17,162,11306,11307,11308,11309,11310,11311], data=list(range(12)), solid=True) def wood(self, blockid, data): # extract orientation and wood type frorm data bits wood_type = data & 3 @@ -1191,7 +1204,7 @@ def wood(self, blockid, data): elif wood_orientation == 8: # north-south orientation return self.build_full_block(side, None, None, side.rotate(270), top) -@material(blockid=[18, 161], data=range(16), transparent=True, solid=True) +@material(blockid=[18, 161], data=list(range(16)), transparent=True, solid=True) def leaves(self, blockid, data): # mask out the bits 4 and 8 # they are used for player placed and check-for-decay blocks @@ -1217,7 +1230,7 @@ block(blockid=21, top_image="assets/minecraft/textures/block/lapis_ore.png") block(blockid=22, top_image="assets/minecraft/textures/block/lapis_block.png") # dispensers, dropper, furnaces, and burning furnaces -@material(blockid=[23, 61, 62, 158], data=range(6), solid=True) +@material(blockid=[23, 61, 62, 158], data=list(range(6)), solid=True) def furnaces(self, blockid, data): # first, do the rotation if needed if self.rotation == 1: @@ -1266,7 +1279,7 @@ def furnaces(self, blockid, data): return self.build_full_block(top, None, None, side, side) # sandstone -@material(blockid=24, data=range(3), solid=True) +@material(blockid=24, data=list(range(3)), solid=True) def sandstone(self, blockid, data): top = self.load_image_texture("assets/minecraft/textures/block/sandstone_top.png") if data == 0: # normal @@ -1277,7 +1290,7 @@ def sandstone(self, blockid, data): return self.build_block(top, self.load_image_texture("assets/minecraft/textures/block/cut_sandstone.png")) # red sandstone -@material(blockid=179, data=range(3), solid=True) +@material(blockid=179, data=list(range(3)), solid=True) def sandstone(self, blockid, data): top = self.load_image_texture("assets/minecraft/textures/block/red_sandstone_top.png") if data == 0: # normal @@ -1291,7 +1304,7 @@ def sandstone(self, blockid, data): # note block block(blockid=25, top_image="assets/minecraft/textures/block/note_block.png") -@material(blockid=26, data=range(12), transparent=True, nospawn=True) +@material(blockid=26, data=list(range(12)), transparent=True, nospawn=True) def bed(self, blockid, data): # first get rotation done # Masked to not clobber block head/foot info @@ -1381,7 +1394,7 @@ def bed(self, blockid, data): return self.build_full_block(top_face, None, None, left_face, right_face) # powered, detector, activator and normal rails -@material(blockid=[27, 28, 66, 157], data=range(14), transparent=True) +@material(blockid=[27, 28, 66, 157], data=list(range(14)), transparent=True) def rails(self, blockid, data): # first, do rotation # Masked to not clobber powered rail on/off info @@ -1664,7 +1677,7 @@ def piston_extension(self, blockid, data): # cobweb sprite(blockid=30, imagename="assets/minecraft/textures/block/cobweb.png", nospawn=True) -@material(blockid=31, data=range(3), transparent=True) +@material(blockid=31, data=list(range(3)), transparent=True) def tall_grass(self, blockid, data): if data == 0: # dead shrub texture = self.load_image_texture("assets/minecraft/textures/block/dead_bush.png") @@ -1678,7 +1691,7 @@ def tall_grass(self, blockid, data): # dead bush billboard(blockid=32, imagename="assets/minecraft/textures/block/dead_bush.png") -@material(blockid=35, data=range(16), solid=True) +@material(blockid=35, data=list(range(16)), solid=True) def wool(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_wool.png" % color_map[data]) @@ -1688,7 +1701,7 @@ def wool(self, blockid, data): sprite(blockid=37, imagename="assets/minecraft/textures/block/dandelion.png") # flowers -@material(blockid=38, data=range(10), transparent=True) +@material(blockid=38, data=list(range(10)), transparent=True) def flower(self, blockid, data): flower_map = ["poppy", "blue_orchid", "allium", "azure_bluet", "red_tulip", "orange_tulip", "white_tulip", "pink_tulip", "oxeye_daisy", "dandelion"] @@ -1708,7 +1721,7 @@ block(blockid=42, top_image="assets/minecraft/textures/block/iron_block.png") # double slabs and slabs # these wooden slabs are unobtainable without cheating, they are still # here because lots of pre-1.3 worlds use this blocks -@material(blockid=[43, 44, 181, 182, 204, 205], data=range(16), transparent=(44,182,205), solid=True) +@material(blockid=[43, 44, 181, 182, 204, 205], data=list(range(16)), transparent=(44,182,205), solid=True) def slabs(self, blockid, data): if blockid == 44 or blockid == 182: texture = data & 7 @@ -1847,7 +1860,7 @@ def torches(self, blockid, data): return img # fire -@material(blockid=51, data=range(16), transparent=True) +@material(blockid=51, data=list(range(16)), transparent=True) def fire(self, blockid, data): firetextures = self.load_fire() side1 = self.transform_image_side(firetextures[0]) @@ -1867,7 +1880,7 @@ def fire(self, blockid, data): block(blockid=52, top_image="assets/minecraft/textures/block/spawner.png", transparent=True) # wooden, cobblestone, red brick, stone brick, netherbrick, sandstone, spruce, birch, jungle, quartz, and red sandstone stairs. -@material(blockid=[53,67,108,109,114,128,134,135,136,156,163,164,180,203], data=range(128), transparent=True, solid=True, nospawn=True) +@material(blockid=[53,67,108,109,114,128,134,135,136,156,163,164,180,203], data=list(range(128)), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # preserve the upside-down bit upside_down = data & 0x4 @@ -1991,7 +2004,7 @@ def stairs(self, blockid, data): # normal, locked (used in april's fool day), ender and trapped chest # NOTE: locked chest used to be id95 (which is now stained glass) -@material(blockid=[54,130,146], data=range(30), transparent = True) +@material(blockid=[54,130,146], data=list(range(30)), transparent = True) def chests(self, blockid, data): # the first 3 bits are the orientation as stored in minecraft, # bits 0x8 and 0x10 indicate which half of the double chest is it. @@ -2188,7 +2201,7 @@ def chests(self, blockid, data): # redstone wire # uses pseudo-ancildata found in iterate.c -@material(blockid=55, data=range(128), transparent=True) +@material(blockid=55, data=list(range(128)), transparent=True) def wire(self, blockid, data): if data & 0b1000000 == 64: # powered redstone wire @@ -2281,7 +2294,7 @@ def crafting_table(self, blockid, data): return img # crops with 8 data values (like wheat) -@material(blockid=59, data=range(8), transparent=True, nospawn=True) +@material(blockid=59, data=list(range(8)), transparent=True, nospawn=True) def crops8(self, blockid, data): raw_crop = self.load_image_texture("assets/minecraft/textures/block/wheat_stage%d.png" % data) crop1 = self.transform_image_top(raw_crop) @@ -2295,7 +2308,7 @@ def crops8(self, blockid, data): return img # farmland and grass path (15/16 blocks) -@material(blockid=[60,208], data=range(9), solid=True) +@material(blockid=[60,208], data=list(range(9)), solid=True) def farmland(self, blockid, data): if blockid == 60: side = self.load_image_texture("assets/minecraft/textures/block/dirt.png") @@ -2315,7 +2328,7 @@ def farmland(self, blockid, data): # signposts -@material(blockid=63, data=range(16), transparent=True) +@material(blockid=63, data=list(range(16)), transparent=True) def signpost(self, blockid, data): # first rotations @@ -2369,7 +2382,7 @@ def signpost(self, blockid, data): # wooden and iron door # uses pseudo-ancildata found in iterate.c -@material(blockid=[64,71,193,194,195,196,197], data=range(32), transparent=True) +@material(blockid=[64,71,193,194,195,196,197], data=list(range(32)), transparent=True) def door(self, blockid, data): #Masked to not clobber block top/bottom & swung info if self.rotation == 1: @@ -2618,7 +2631,7 @@ def wall_sign(self, blockid, data): # wall sign return img # levers -@material(blockid=69, data=range(16), transparent=True) +@material(blockid=69, data=list(range(16)), transparent=True) def levers(self, blockid, data): if data & 8 == 8: powered = True else: powered = False @@ -2802,7 +2815,7 @@ def pressure_plate(self, blockid, data): block(blockid=[73, 74], top_image="assets/minecraft/textures/block/redstone_ore.png") # stone a wood buttons -@material(blockid=(77,143,11326,11327,11328,11329,11330), data=range(16), transparent=True) +@material(blockid=(77,143,11326,11327,11328,11329,11330), data=list(range(16)), transparent=True) def buttons(self, blockid, data): # 0x8 is set if the button is pressed mask this info and render @@ -2899,7 +2912,7 @@ def buttons(self, blockid, data): return img # snow -@material(blockid=78, data=range(16), transparent=True, solid=True) +@material(blockid=78, data=list(range(16)), transparent=True, solid=True) def snow(self, blockid, data): # still not rendered correctly: data other than 0 @@ -2926,7 +2939,7 @@ def snow(self, blockid, data): block(blockid=80, top_image="assets/minecraft/textures/block/snow.png") # cactus -@material(blockid=81, data=range(15), transparent=True, solid=True, nospawn=True) +@material(blockid=81, data=list(range(15)), transparent=True, solid=True, nospawn=True) def cactus(self, blockid, data): top = self.load_image_texture("assets/minecraft/textures/block/cactus_top.png") side = self.load_image_texture("assets/minecraft/textures/block/cactus_side.png") @@ -2954,19 +2967,19 @@ def cactus(self, blockid, data): block(blockid=82, top_image="assets/minecraft/textures/block/clay.png") # sugar cane -@material(blockid=83, data=range(16), transparent=True) +@material(blockid=83, data=list(range(16)), transparent=True) def sugar_cane(self, blockid, data): tex = self.load_image_texture("assets/minecraft/textures/block/sugar_cane.png") return self.build_sprite(tex) # jukebox -@material(blockid=84, data=range(16), solid=True) +@material(blockid=84, data=list(range(16)), solid=True) def jukebox(self, blockid, data): return self.build_block(self.load_image_texture("assets/minecraft/textures/block/jukebox_top.png"), self.load_image_texture("assets/minecraft/textures/block/note_block.png")) # nether and normal fences # uses pseudo-ancildata found in iterate.c -@material(blockid=[85, 188, 189, 190, 191, 192, 113], data=range(16), transparent=True, nospawn=True) +@material(blockid=[85, 188, 189, 190, 191, 192, 113], data=list(range(16)), transparent=True, nospawn=True) def fence(self, blockid, data): # no need for rotations, it uses pseudo data. # create needed images for Big stick fence @@ -3082,7 +3095,7 @@ def fence(self, blockid, data): return img # pumpkin -@material(blockid=[86, 91,11300], data=range(4), solid=True) +@material(blockid=[86, 91,11300], data=list(range(4)), solid=True) def pumpkin(self, blockid, data): # pumpkins, jack-o-lantern # rotation if self.rotation == 1: @@ -3149,7 +3162,7 @@ def portal(self, blockid, data): return img # cake! -@material(blockid=92, data=range(6), transparent=True, nospawn=True) +@material(blockid=92, data=list(range(6)), transparent=True, nospawn=True) def cake(self, blockid, data): # cake textures @@ -3273,7 +3286,7 @@ def cake(self, blockid, data): return img # redstone repeaters ON and OFF -@material(blockid=[93,94], data=range(16), transparent=True, nospawn=True) +@material(blockid=[93,94], data=list(range(16)), transparent=True, nospawn=True) def repeater(self, blockid, data): # rotation # Masked to not clobber delay info @@ -3418,7 +3431,7 @@ def repeater(self, blockid, data): return img # redstone comparator (149 is inactive, 150 is active) -@material(blockid=[149,150], data=range(16), transparent=True, nospawn=True) +@material(blockid=[149,150], data=list(range(16)), transparent=True, nospawn=True) def comparator(self, blockid, data): # rotation @@ -3483,7 +3496,7 @@ def comparator(self, blockid, data): # trapdoor # the trapdoor is looks like a sprite when opened, that's not good -@material(blockid=[96,167,11332,11333,11334,11335,11336], data=range(16), transparent=True, nospawn=True) +@material(blockid=[96,167,11332,11333,11334,11335,11336], data=list(range(16)), transparent=True, nospawn=True) def trapdoor(self, blockid, data): # rotation @@ -3539,7 +3552,7 @@ def trapdoor(self, blockid, data): return img # block with hidden silverfish (stone, cobblestone and stone brick) -@material(blockid=97, data=range(3), solid=True) +@material(blockid=97, data=list(range(3)), solid=True) def hidden_silverfish(self, blockid, data): if data == 0: # stone t = self.load_image_texture("assets/minecraft/textures/block/stone.png") @@ -3553,7 +3566,7 @@ def hidden_silverfish(self, blockid, data): return img # stone brick -@material(blockid=98, data=range(4), solid=True) +@material(blockid=98, data=list(range(4)), solid=True) def stone_brick(self, blockid, data): if data == 0: # normal t = self.load_image_texture("assets/minecraft/textures/block/stone_bricks.png") @@ -3569,7 +3582,7 @@ def stone_brick(self, blockid, data): return img # huge brown and red mushroom -@material(blockid=[99,100], data= range(11) + [14,15], solid=True) +@material(blockid=[99,100], data= list(range(11)) + [14,15], solid=True) def huge_mushroom(self, blockid, data): # rotation if self.rotation == 1: @@ -3653,7 +3666,7 @@ def huge_mushroom(self, blockid, data): # iron bars and glass pane # TODO glass pane is not a sprite, it has a texture for the side, # at the moment is not used -@material(blockid=[101,102, 160], data=range(256), transparent=True, nospawn=True) +@material(blockid=[101,102, 160], data=list(range(256)), transparent=True, nospawn=True) def panes(self, blockid, data): # no rotation, uses pseudo data if blockid == 101: @@ -3705,7 +3718,7 @@ block(blockid=103, top_image="assets/minecraft/textures/block/melon_top.png", si # TODO To render it as in game needs from pseudo data and ancil data: # once fully grown the stem bends to the melon/pumpkin block, # at the moment only render the growing stem -@material(blockid=[104,105], data=range(8), transparent=True) +@material(blockid=[104,105], data=list(range(8)), transparent=True) def stem(self, blockid, data): # the ancildata value indicates how much of the texture # is shown. @@ -3725,7 +3738,7 @@ def stem(self, blockid, data): # vines -@material(blockid=106, data=range(16), transparent=True) +@material(blockid=106, data=list(range(16)), transparent=True) def vines(self, blockid, data): # rotation # vines data is bit coded. decode it first. @@ -3766,7 +3779,7 @@ def vines(self, blockid, data): return img # fence gates -@material(blockid=[107, 183, 184, 185, 186, 187], data=range(8), transparent=True, nospawn=True) +@material(blockid=[107, 183, 184, 185, 186, 187], data=list(range(8)), transparent=True, nospawn=True) def fence_gate(self, blockid, data): # rotation @@ -3870,7 +3883,7 @@ block(blockid=110, top_image="assets/minecraft/textures/block/mycelium_top.png", # At the moment of writing this lilypads has no ancil data and their # orientation depends on their position on the map. So it uses pseudo # ancildata. -@material(blockid=111, data=range(4), transparent=True) +@material(blockid=111, data=list(range(4)), transparent=True) def lilypad(self, blockid, data): t = self.load_image_texture("assets/minecraft/textures/block/lily_pad.png").copy() if data == 0: @@ -3888,7 +3901,7 @@ def lilypad(self, blockid, data): block(blockid=112, top_image="assets/minecraft/textures/block/nether_bricks.png") # nether wart -@material(blockid=115, data=range(4), transparent=True) +@material(blockid=115, data=list(range(4)), transparent=True) def nether_wart(self, blockid, data): if data == 0: # just come up t = self.load_image_texture("assets/minecraft/textures/block/nether_wart_stage0.png") @@ -3915,7 +3928,7 @@ def enchantment_table(self, blockid, data): # brewing stand # TODO this is a place holder, is a 2d image pasted -@material(blockid=117, data=range(5), transparent=True) +@material(blockid=117, data=list(range(5)), transparent=True) def brewing_stand(self, blockid, data): base = self.load_image_texture("assets/minecraft/textures/block/brewing_stand_base.png") img = self.build_full_block(None, None, None, None, None, base) @@ -3925,7 +3938,7 @@ def brewing_stand(self, blockid, data): return img # cauldron -@material(blockid=118, data=range(4), transparent=True) +@material(blockid=118, data=list(range(4)), transparent=True) def cauldron(self, blockid, data): side = self.load_image_texture("assets/minecraft/textures/block/cauldron_side.png") top = self.load_image_texture("assets/minecraft/textures/block/cauldron_top.png") @@ -3971,7 +3984,7 @@ def end_portal(self, blockid, data): return img # end portal frame (data range 8 to get all orientations of filled) -@material(blockid=120, data=range(8), transparent=True) +@material(blockid=120, data=list(range(8)), transparent=True) def end_portal_frame(self, blockid, data): # The bottom 2 bits are oritation info but seems there is no # graphical difference between orientations @@ -4046,7 +4059,7 @@ def daylight_sensor(self, blockid, data): # wooden double and normal slabs # these are the new wooden slabs, blockids 43 44 still have wooden # slabs, but those are unobtainable without cheating -@material(blockid=[125, 126], data=range(16), transparent=(44,), solid=True) +@material(blockid=[125, 126], data=list(range(16)), transparent=(44,), solid=True) def wooden_slabs(self, blockid, data): texture = data & 7 if texture== 0: # oak @@ -4076,7 +4089,7 @@ block(blockid=129, top_image="assets/minecraft/textures/block/emerald_ore.png") block(blockid=133, top_image="assets/minecraft/textures/block/emerald_block.png") # cocoa plant -@material(blockid=127, data=range(12), transparent=True) +@material(blockid=127, data=list(range(12)), transparent=True) def cocoa_plant(self, blockid, data): orientation = data & 3 # rotation @@ -4198,7 +4211,7 @@ def beacon(self, blockid, data): # cobblestone and mossy cobblestone walls, chorus plants # one additional bit of data value added for mossy and cobblestone -@material(blockid=[139, 199], data=range(32), transparent=True, nospawn=True) +@material(blockid=[139, 199], data=list(range(32)), transparent=True, nospawn=True) def cobblestone_wall(self, blockid, data): # chorus plants if blockid == 199: @@ -4329,7 +4342,7 @@ def cobblestone_wall(self, blockid, data): return img # carrots, potatoes -@material(blockid=[141,142], data=range(8), transparent=True, nospawn=True) +@material(blockid=[141,142], data=list(range(8)), transparent=True, nospawn=True) def crops4(self, blockid, data): # carrots and potatoes have 8 data, but only 4 visual stages stage = {0:0, @@ -4355,7 +4368,7 @@ def crops4(self, blockid, data): return img # anvils -@material(blockid=145, data=range(12), transparent=True) +@material(blockid=145, data=list(range(12)), transparent=True) def anvil(self, blockid, data): # anvils only have two orientations, invert it for rotations 1 and 3 @@ -4447,7 +4460,7 @@ block(blockid=152, top_image="assets/minecraft/textures/block/redstone_block.png block(blockid=153, top_image="assets/minecraft/textures/block/nether_quartz_ore.png") # block of quartz -@material(blockid=155, data=range(5), solid=True) +@material(blockid=155, data=list(range(5)), solid=True) def quartz_block(self, blockid, data): if data in (0,1): # normal and chiseled quartz block @@ -4475,7 +4488,7 @@ def quartz_block(self, blockid, data): return self.build_full_block(side.rotate(90), None, None, top, side.rotate(90)) # hopper -@material(blockid=154, data=range(4), transparent=True) +@material(blockid=154, data=list(range(4)), transparent=True) def hopper(self, blockid, data): #build the top side = self.load_image_texture("assets/minecraft/textures/block/hopper_outside.png") @@ -4502,7 +4515,7 @@ def hopper(self, blockid, data): block(blockid=165, top_image="assets/minecraft/textures/block/slime_block.png") # prismarine block -@material(blockid=168, data=range(3), solid=True) +@material(blockid=168, data=list(range(3)), solid=True) def prismarine_block(self, blockid, data): if data == 0: # prismarine @@ -4520,7 +4533,7 @@ def prismarine_block(self, blockid, data): block(blockid=169, top_image="assets/minecraft/textures/block/sea_lantern.png") # hay block -@material(blockid=170, data=range(9), solid=True) +@material(blockid=170, data=list(range(9)), solid=True) def hayblock(self, blockid, data): top = self.load_image_texture("assets/minecraft/textures/block/hay_block_top.png") side = self.load_image_texture("assets/minecraft/textures/block/hay_block_side.png") @@ -4542,7 +4555,7 @@ def hayblock(self, blockid, data): # carpet - wool block that's small? -@material(blockid=171, data=range(16), transparent=True) +@material(blockid=171, data=list(range(16)), transparent=True) def carpet(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_wool.png" % color_map[data]) @@ -4552,7 +4565,7 @@ def carpet(self, blockid, data): block(blockid=172, top_image="assets/minecraft/textures/block/terracotta.png") #stained hardened clay -@material(blockid=159, data=range(16), solid=True) +@material(blockid=159, data=list(range(16)), solid=True) def stained_clay(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_terracotta.png" % color_map[data]) @@ -4586,7 +4599,7 @@ block(blockid=11323, top_image="assets/minecraft/textures/block/dead_fire_coral_ block(blockid=11324, top_image="assets/minecraft/textures/block/dead_horn_coral_block.png") block(blockid=11325, top_image="assets/minecraft/textures/block/dead_tube_coral_block.png") -@material(blockid=175, data=range(16), transparent=True) +@material(blockid=175, data=list(range(16)), transparent=True) def flower(self, blockid, data): double_plant_map = ["sunflower", "lilac", "tall_grass", "large_fern", "rose_bush", "peony", "peony", "peony"] plant = double_plant_map[data & 0x7] @@ -4608,7 +4621,7 @@ def flower(self, blockid, data): return img # chorus flower -@material(blockid=200, data=range(6), solid=True) +@material(blockid=200, data=list(range(6)), solid=True) def chorus_flower(self, blockid, data): # aged 5, dead if data == 5: @@ -4622,7 +4635,7 @@ def chorus_flower(self, blockid, data): block(blockid=201, top_image="assets/minecraft/textures/block/purpur_block.png") # purpur pilar -@material(blockid=202, data=range(12) , solid=True) +@material(blockid=202, data=list(range(12)) , solid=True) def purpur_pillar(self, blockid, data): pillar_orientation = data & 12 top=self.load_image_texture("assets/minecraft/textures/block/purpur_pillar_top.png") @@ -4639,7 +4652,7 @@ def purpur_pillar(self, blockid, data): block(blockid=206, top_image="assets/minecraft/textures/block/end_stone_bricks.png") # frosted ice -@material(blockid=212, data=range(4), solid=True) +@material(blockid=212, data=list(range(4)), solid=True) def frosted_ice(self, blockid, data): img = self.load_image_texture("assets/minecraft/textures/block/frosted_ice_%d.png" % data) return self.build_block(img, img) @@ -4653,7 +4666,7 @@ block(blockid=214, top_image="assets/minecraft/textures/block/nether_wart_block. # red nether brick block(blockid=215, top_image="assets/minecraft/textures/block/red_nether_bricks.png") -@material(blockid=216, data=range(12), solid=True) +@material(blockid=216, data=list(range(12)), solid=True) def boneblock(self, blockid, data): # extract orientation boneblock_orientation = data & 12 @@ -4676,7 +4689,7 @@ def boneblock(self, blockid, data): return self.build_full_block(side, None, None, side.rotate(270), top) # observer -@material(blockid=218, data=range(6), solid=True, nospawn=True) +@material(blockid=218, data=list(range(6)), solid=True, nospawn=True) def observer(self, blockid, data): # first, do the rotation if needed if self.rotation == 1: @@ -4718,7 +4731,7 @@ def observer(self, blockid, data): return img # shulker box -@material(blockid=range(219,235), data=range(6), solid=True, nospawn=True) +@material(blockid=list(range(219,235)), data=list(range(6)), solid=True, nospawn=True) def shulker_box(self, blockid, data): # first, do the rotation if needed data = data & 7 @@ -4741,15 +4754,15 @@ def shulker_box(self, blockid, data): color = color_map[blockid - 219] shulker_t = self.load_image_texture("assets/minecraft/textures/entity/shulker/shulker_%s.png" % color).copy() w,h = shulker_t.size - res = w / 4 + res = w // 4 # Cut out the parts of the shulker texture we need for the box - top = shulker_t.crop((res,0,res*2,res)) - bottom = shulker_t.crop((res*2,int(res*1.75),res*3,int(res*2.75))) - side_top = shulker_t.crop((0,res,res,int(res*1.75))) - side_bottom = shulker_t.crop((0,int(res*2.75),res,int(res*3.25))) - side = Image.new('RGBA', (res,res)) - side.paste(side_top, (0,0), side_top) - side.paste(side_bottom, (0,res/2), side_bottom) + top = shulker_t.crop((res, 0, res * 2, res)) + bottom = shulker_t.crop((res * 2, int(res * 1.75), res * 3, int(res * 2.75))) + side_top = shulker_t.crop((0, res, res, int(res * 1.75))) + side_bottom = shulker_t.crop((0, int(res * 2.75), res, int(res * 3.25))) + side = Image.new('RGBA', (res, res)) + side.paste(side_top, (0, 0), side_top) + side.paste(side_bottom, (0, res // 2), side_bottom) if data == 0: # down side = side.rotate(180) @@ -4768,7 +4781,7 @@ def shulker_box(self, blockid, data): return img # structure block -@material(blockid=255, data=range(4), solid=True) +@material(blockid=255, data=list(range(4)), solid=True) def structure_block(self, blockid, data): if data == 0: img = self.load_image_texture("assets/minecraft/textures/block/structure_block_save.png") @@ -4781,7 +4794,7 @@ def structure_block(self, blockid, data): return self.build_block(img, img) # beetroots -@material(blockid=207, data=range(4), transparent=True, nospawn=True) +@material(blockid=207, data=list(range(4)), transparent=True, nospawn=True) def crops(self, blockid, data): raw_crop = self.load_image_texture("assets/minecraft/textures/block/beetroots_stage%d.png" % data) crop1 = self.transform_image_top(raw_crop) @@ -4795,19 +4808,19 @@ def crops(self, blockid, data): return img # Concrete -@material(blockid=251, data=range(16), solid=True) +@material(blockid=251, data=list(range(16)), solid=True) def concrete(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_concrete.png" % color_map[data]) return self.build_block(texture, texture) # Concrete Powder -@material(blockid=252, data=range(16), solid=True) +@material(blockid=252, data=list(range(16)), solid=True) def concrete(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_concrete_powder.png" % color_map[data]) return self.build_block(texture, texture) # Glazed Terracotta -@material(blockid=range(235,251), data=range(8), solid=True) +@material(blockid=list(range(235,251)), data=list(range(8)), solid=True) def glazed_terracotta(self, blockid, data): texture = self.load_image_texture("assets/minecraft/textures/block/%s_glazed_terracotta.png" % color_map[blockid - 235]) glazed_terracotta_orientation = data & 3 diff --git a/overviewer_core/tileset.py b/overviewer_core/tileset.py index 5dbac43..4128e5a 100644 --- a/overviewer_core/tileset.py +++ b/overviewer_core/tileset.py @@ -26,13 +26,13 @@ import stat import sys import time from collections import namedtuple -from itertools import chain, izip, product +from itertools import chain, product from PIL import Image -import c_overviewer -import rendermodes -from c_overviewer import resize_half +from . import c_overviewer +from . import rendermodes +from .c_overviewer import resize_half from . import nbt, world from .files import FileReplacer, get_fs_caps @@ -95,7 +95,7 @@ do_work(workobj) # small but useful def iterate_base4(d): """Iterates over a base 4 number with d digits""" - return product(xrange(4), repeat=d) + return product(range(4), repeat=d) # A named tuple class storing the row and column bounds for the to-be-rendered @@ -646,7 +646,7 @@ class TileSet(object): bounds = self._find_chunk_range() # Calculate the depth of the tree - for p in xrange(2, 33): # max 32 + for p in range(2, 33): # max 32 # Will 2^p tiles wide and high suffice? # X has twice as many chunks as tiles, then halved since this is a @@ -686,13 +686,13 @@ class TileSet(object): if self.treedepth > curdepth: logging.warning("Your map seems to have expanded beyond its previous bounds.") logging.warning("Doing some tile re-arrangements... just a sec...") - for _ in xrange(self.treedepth - curdepth): + for _ in range(self.treedepth - curdepth): self._increase_depth() elif self.treedepth < curdepth: logging.warning( "Your map seems to have shrunk. Did you delete some " "chunks? No problem. Re-arranging tiles, just a sec...") - for _ in xrange(curdepth - self.treedepth): + for _ in range(curdepth - self.treedepth): self._decrease_depth() logging.info( "There, done. I'm switching to --check-tiles mode for " @@ -798,12 +798,12 @@ class TileSet(object): os.rename(getpath("new3"), getpath("3")) # Delete the files in the top directory to make sure they get re-created. - files = [str(num) + "." + self.imgextension for num in xrange(4)] + \ + files = [str(num) + "." + self.imgextension for num in range(4)] + \ ["base." + self.imgextension] for f in files: try: os.unlink(getpath(f)) - except OSError, e: + except OSError as e: # Ignore file doesn't exist errors if e.errno != errno.ENOENT: raise @@ -964,7 +964,7 @@ class TileSet(object): if not quadPath_filtered: try: os.unlink(imgpath) - except OSError, e: + except OSError as e: # Ignore errors if it's "file doesn't exist" if e.errno != errno.ENOENT: raise @@ -988,14 +988,14 @@ class TileSet(object): quad = Image.new("RGBA", (192, 192), self.options['bgcolor']) resize_half(quad, src) img.paste(quad, path[0]) - except Exception, e: + except Exception as e: logging.warning("Couldn't open %s. It may be corrupt. Error was '%s'.", path[1], e) logging.warning( "I'm going to try and delete it. You will need to run " "the render again and with --check-tiles.") try: os.unlink(path[1]) - except Exception, e: + except Exception as e: logging.error( "While attempting to delete corrupt image %s, an error was encountered. " "You will need to delete it yourself. Error was '%s'", path[1], e) @@ -1016,7 +1016,7 @@ class TileSet(object): try: os.utime(tmppath, (max_mtime, max_mtime)) - except OSError, e: + except OSError as e: # Ignore errno ENOENT: file does not exist. Due to a race # condition, two processes could conceivably try and update # the same temp file at the same time @@ -1049,7 +1049,7 @@ class TileSet(object): "This may be a bug.", tile) try: os.unlink(imgpath) - except OSError, e: + except OSError as e: # ignore only if the error was "file not found" if e.errno != errno.ENOENT: raise @@ -1062,7 +1062,7 @@ class TileSet(object): if not os.path.exists(dirdest): try: os.makedirs(dirdest) - except OSError, e: + except OSError as e: # Ignore errno EEXIST: file exists. Due to a race condition, # two processes could conceivably try and create the same # directory at the same time @@ -1098,7 +1098,7 @@ class TileSet(object): # Some chunks are present on disk but not fully initialized. # This is okay. pass - except Exception, e: + except Exception as e: logging.error("Could not render chunk %s,%s for some reason. " "This is likely a render primitive option error.", chunkx, chunkz) logging.error("Full error was:", exc_info=1) @@ -1154,7 +1154,7 @@ class TileSet(object): imgpath = tileobj.get_filepath(self.outputdir, self.imgextension) try: tile_mtime = os.stat(imgpath)[stat.ST_MTIME] - except OSError, e: + except OSError as e: if e.errno != errno.ENOENT: raise tile_mtime = 0 @@ -1198,7 +1198,7 @@ class TileSet(object): max_child_mtime = 0 # First, recurse to each of our children - for childnum in xrange(4): + for childnum in range(4): childpath = path + (childnum,) # Check if this sub-tree should actually exist, so that we only @@ -1238,7 +1238,7 @@ class TileSet(object): logging.debug("Testing mtime for composite-tile %s", imgpath) try: tile_mtime = os.stat(imgpath)[stat.ST_MTIME] - except OSError, e: + except OSError as e: if e.errno != errno.ENOENT: raise tile_mtime = 0 @@ -1296,7 +1296,7 @@ def unconvert_coords(col, row): # col + row = chunkz + chunkz => (col + row)/2 = chunkz # col - row = chunkx + chunkx => (col - row)/2 = chunkx - return ((col - row) / 2, (col + row) / 2) + return ((col - row) // 2, (col + row) // 2) ###################### @@ -1325,9 +1325,9 @@ def get_tiles_by_chunk(chunkcol, chunkrow): # tile above it as well. Also touches the next 4 tiles down (16 # rows) if chunkrow % 4 == 0: - rowrange = xrange(tilerow - 4, tilerow + 32 + 1, 4) + rowrange = range(tilerow - 4, tilerow + 32 + 1, 4) else: - rowrange = xrange(tilerow, tilerow + 32 + 1, 4) + rowrange = range(tilerow, tilerow + 32 + 1, 4) return product(colrange, rowrange) @@ -1358,13 +1358,13 @@ def get_chunks_by_tile(tile, regionset): # First do the odd. For each chunk in the tile's odd column the tile # "passes through" three chunk sections. oddcol_sections = [] - for i, y in enumerate(reversed(xrange(16))): - for row in xrange(tile.row + 3 - i * 2, tile.row - 2 - i * 2, -2): + for i, y in enumerate(reversed(range(16))): + for row in range(tile.row + 3 - i * 2, tile.row - 2 - i * 2, -2): oddcol_sections.append((tile.col + 1, row, y)) evencol_sections = [] - for i, y in enumerate(reversed(xrange(16))): - for row in xrange(tile.row + 4 - i * 2, tile.row - 3 - i * 2, -2): + for i, y in enumerate(reversed(range(16))): + for row in range(tile.row + 4 - i * 2, tile.row - 3 - i * 2, -2): evencol_sections.append((tile.col + 2, row, y)) evencol_sections.append((tile.col, row, y)) @@ -1589,7 +1589,7 @@ class RendertileSet(object): # or more of the children down the tree are True. return True - def __nonzero__(self): + def __bool__(self): """Returns the boolean context of this particular node. If any descendent of this node is True return True. Otherwise, False. @@ -1604,8 +1604,8 @@ class RendertileSet(object): # XXX There seems to be something wrong with the num_tiles calculation. # Calculate the number of tiles by iteration and emit a warning if it # does not match. - from itertools import imap - num = sum(imap(lambda _: 1, self.iterate())) + + num = sum(map(lambda _: 1, self.iterate())) if num != self.num_tiles: logging.error("Please report this to the developers: RendertileSet num_tiles=%r, " "count=%r, children=%r", self.num_tiles, num, self.children) @@ -1619,22 +1619,23 @@ class RendertileSet(object): # XXX There seems to be something wrong with the num_tiles calculation. # Calculate the number of tiles by iteration and emit a warning if it # does not match. - from itertools import imap - num = sum(imap(lambda _: 1, self.posttraversal())) + + num = sum(map(lambda _: 1, self.posttraversal())) if num != self.num_tiles_all: logging.error("Please report this to the developers: RendertileSet num_tiles_all=%r, " "count_all=%r, children=%r", self.num_tiles, num, self.children) return num -def distance_sort(children, (off_x, off_y)): +def distance_sort(children, xxx_todo_changeme): + (off_x, off_y) = xxx_todo_changeme order = [] - for child, (dx, dy) in izip(children, [(-1, -1), (1, -1), (-1, 1), (1, 1)]): + for child, (dx, dy) in zip(children, [(-1, -1), (1, -1), (-1, 1), (1, 1)]): x = off_x * 2 + dx y = off_y * 2 + dy order.append((child, (x, y))) - return sorted(order, key=lambda (_, (x, y)): x * x + y * y) + return sorted(order, key=lambda __x_y: __x_y[1][0] * __x_y[1][0] + __x_y[1][1] * __x_y[1][1]) class RenderTile(object): @@ -1733,7 +1734,7 @@ class RenderTile(object): path = [] - for level in xrange(depth): + for level in range(depth): # Strategy: Find the midpoint of this level, and determine which # quadrant this row/col is in. Then set the bounds to that level # and repeat diff --git a/overviewer_core/util.py b/overviewer_core/util.py index 324195a..2e130e9 100644 --- a/overviewer_core/util.py +++ b/overviewer_core/util.py @@ -48,7 +48,7 @@ def findGitHash(): return line except Exception: try: - import overviewer_version + from . import overviewer_version return overviewer_version.HASH except Exception: pass @@ -77,7 +77,7 @@ def findGitVersion(): return line except Exception: try: - import overviewer_version + from . import overviewer_version return overviewer_version.VERSION except Exception: return "unknown" @@ -108,7 +108,7 @@ def nice_exit(ret=0): if ret and is_bare_console(): print("") print("Press [Enter] to close this window.") - raw_input() + input() sys.exit(ret) @@ -117,7 +117,7 @@ def roundrobin(iterables): "roundrobin('ABC', 'D', 'EF') --> A D E B F C" # Recipe credited to George Sakkis pending = len(iterables) - nexts = cycle(iter(it).next for it in iterables) + nexts = cycle(iter(it).__next__ for it in iterables) while pending: try: for next in nexts: @@ -136,281 +136,13 @@ def dict_subset(d, keys): return n -# (from http://code.activestate.com/recipes/576693/ [r9]) -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. -try: - from thread import get_ident as _get_ident -except ImportError: - from dummy_thread import get_ident as _get_ident - -try: - from _abcoll import KeysView, ValuesView, ItemsView -except ImportError: - pass - - -class OrderedDict(dict): - 'Dictionary that remembers insertion order' - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running={}): - 'od.__repr__() <==> repr(od)' - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self) == len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) - - -# now replace all that with the official version, if available -try: - import collections - OrderedDict = collections.OrderedDict -except (ImportError, AttributeError): - pass - - def pid_exists(pid): # http://stackoverflow.com/a/6940314/1318435 """Check whether pid exists in the current process table.""" if pid < 0: return False try: os.kill(pid, 0) - except OSError, e: + except OSError as e: return e.errno != errno.ESRCH else: return True diff --git a/overviewer_core/world.py b/overviewer_core/world.py index 1e7d2b3..77db363 100644 --- a/overviewer_core/world.py +++ b/overviewer_core/world.py @@ -53,7 +53,7 @@ def log_other_exceptions(func): return func(*args) except ChunkDoesntExist: raise - except Exception, e: + except Exception as e: logging.exception("%s raised this exception", func.func_name) raise return newfunc @@ -1139,7 +1139,7 @@ class RegionSet(object): try: region = self._get_regionobj(regionfile) data = region.load_chunk(x, z) - except nbt.CorruptionError, e: + except nbt.CorruptionError as e: tries -= 1 if tries > 0: # Flush the region cache to possibly read a new region file @@ -1251,7 +1251,7 @@ class RegionSet(object): """ - for (regionx, regiony), (regionfile, filemtime) in self.regionfiles.iteritems(): + for (regionx, regiony), (regionfile, filemtime) in self.regionfiles.items(): try: mcr = self._get_regionobj(regionfile) except nbt.CorruptRegionError: @@ -1267,7 +1267,7 @@ class RegionSet(object): """ - for (regionx, regiony), (regionfile, filemtime) in self.regionfiles.iteritems(): + for (regionx, regiony), (regionfile, filemtime) in self.regionfiles.items(): """ SKIP LOADING A REGION WHICH HAS NOT BEEN MODIFIED! """ if (filemtime < mtime): continue @@ -1561,7 +1561,6 @@ def get_worlds(): "Returns {world # or name : level.dat information}" ret = {} save_dir = get_save_dir() - loc = locale.getpreferredencoding() # No dirs found - most likely not running from inside minecraft-dir if not save_dir is None: @@ -1571,14 +1570,15 @@ def get_worlds(): if not os.path.exists(world_dat): continue try: info = nbt.load(world_dat)[1] - info['Data']['path'] = os.path.join(save_dir, dir).decode(loc) + info['Data']['path'] = os.path.join(save_dir, dir) if 'LevelName' in info['Data'].keys(): ret[info['Data']['LevelName']] = info['Data'] except nbt.CorruptNBTError: - ret[os.path.basename(world_path).decode(loc) + " (corrupt)"] = {'path': world_path.decode(loc), - 'LastPlayed': 0, - 'Time': 0, - 'IsCorrupt': True} + ret[os.path.basename(world_path) + " (corrupt)"] = { + 'path': world_path, + 'LastPlayed': 0, + 'Time': 0, + 'IsCorrupt': True} for dir in os.listdir("."): diff --git a/setup.py b/setup.py index 4163147..e0274e8 100755 --- a/setup.py +++ b/setup.py @@ -1,15 +1,15 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import sys import traceback + # quick version check -if not (sys.version_info[0] == 2 and sys.version_info[1] >= 6): - print("Sorry, the Overviewer requires at least Python 2.6 to run") - if sys.version_info[0] >= 3: - print("and will not run on Python 3.0 or later") +if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 4): + print("Sorry, the Overviewer requires at least Python 3.4 to run.") sys.exit(1) + from distutils.core import setup from distutils.extension import Extension from distutils.command.build import build @@ -176,12 +176,12 @@ for name in glob.glob("overviewer_core/src/primitives/*.c"): primitives.append(name) c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c'] -c_overviewer_files += map(lambda mode: 'primitives/%s.c' % (mode,), primitives) +c_overviewer_files += ['primitives/%s.c' % (mode) for mode in primitives] c_overviewer_files += ['Draw.c'] c_overviewer_includes = ['overviewer.h', 'rendermodes.h'] -c_overviewer_files = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_files) -c_overviewer_includes = map(lambda s: 'overviewer_core/src/'+s, c_overviewer_includes) +c_overviewer_files = ['overviewer_core/src/' + s for s in c_overviewer_files] +c_overviewer_includes = ['overviewer_core/src/' + s for s in c_overviewer_includes] setup_kwargs['ext_modules'].append(Extension('overviewer_core.c_overviewer', c_overviewer_files, include_dirs=['.', numpy_include] + pil_include, depends=c_overviewer_includes, extra_link_args=[])) diff --git a/test/test_all.py b/test/test_all.py index 5905bab..2d6b110 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import unittest # For convenience diff --git a/test/test_cache.py b/test/test_cache.py index 3a66563..35ff3d2 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -9,15 +9,15 @@ class TestLRU(unittest.TestCase): def test_single_insert(self): self.lru[1] = 2 - self.assertEquals(self.lru[1], 2) + self.assertEqual(self.lru[1], 2) def test_multiple_insert(self): self.lru[1] = 2 self.lru[3] = 4 self.lru[5] = 6 - self.assertEquals(self.lru[1], 2) - self.assertEquals(self.lru[3], 4) - self.assertEquals(self.lru[5], 6) + self.assertEqual(self.lru[1], 2) + self.assertEqual(self.lru[3], 4) + self.assertEqual(self.lru[5], 6) def test_full(self): self.lru[1] = 'asdf' @@ -27,11 +27,11 @@ class TestLRU(unittest.TestCase): self.lru[5] = 'asdf' self.lru[6] = 'asdf' self.assertRaises(KeyError, self.lru.__getitem__, 1) - self.assertEquals(self.lru[2], 'asdf') - self.assertEquals(self.lru[3], 'asdf') - self.assertEquals(self.lru[4], 'asdf') - self.assertEquals(self.lru[5], 'asdf') - self.assertEquals(self.lru[6], 'asdf') + self.assertEqual(self.lru[2], 'asdf') + self.assertEqual(self.lru[3], 'asdf') + self.assertEqual(self.lru[4], 'asdf') + self.assertEqual(self.lru[5], 'asdf') + self.assertEqual(self.lru[6], 'asdf') def test_lru(self): self.lru[1] = 'asdf' @@ -40,17 +40,17 @@ class TestLRU(unittest.TestCase): self.lru[4] = 'asdf' self.lru[5] = 'asdf' - self.assertEquals(self.lru[1], 'asdf') - self.assertEquals(self.lru[2], 'asdf') - self.assertEquals(self.lru[4], 'asdf') - self.assertEquals(self.lru[5], 'asdf') + self.assertEqual(self.lru[1], 'asdf') + self.assertEqual(self.lru[2], 'asdf') + self.assertEqual(self.lru[4], 'asdf') + self.assertEqual(self.lru[5], 'asdf') # 3 should be evicted now self.lru[6] = 'asdf' self.assertRaises(KeyError, self.lru.__getitem__, 3) - self.assertEquals(self.lru[1], 'asdf') - self.assertEquals(self.lru[2], 'asdf') - self.assertEquals(self.lru[4], 'asdf') - self.assertEquals(self.lru[5], 'asdf') - self.assertEquals(self.lru[6], 'asdf') + self.assertEqual(self.lru[1], 'asdf') + self.assertEqual(self.lru[2], 'asdf') + self.assertEqual(self.lru[4], 'asdf') + self.assertEqual(self.lru[5], 'asdf') + self.assertEqual(self.lru[6], 'asdf') diff --git a/test/test_rendertileset.py b/test/test_rendertileset.py index 28153cb..f5dddd2 100644 --- a/test/test_rendertileset.py +++ b/test/test_rendertileset.py @@ -1,6 +1,6 @@ import unittest -from itertools import chain, izip +from itertools import chain from overviewer_core.tileset import iterate_base4, RendertileSet from overviewer_core.util import roundrobin @@ -150,7 +150,7 @@ class RendertileSetTest(unittest.TestCase): self.assertRaises(AssertionError, self.test_iterate) def test_count(self): - self.assertEquals(self.tree.count(), len(self.tile_paths)) + self.assertEqual(self.tree.count(), len(self.tile_paths)) def test_bool(self): "Tests the boolean status of a node" @@ -202,7 +202,7 @@ class RendertileSetTest(unittest.TestCase): """Test a post-traversal of the tree's dirty tiles""" # Expect the results in this proper order. iterator = iter(self.tree.posttraversal()) - for expected, actual in izip(self.tile_paths_posttraversal, iterator): + for expected, actual in zip(self.tile_paths_posttraversal, iterator): self.assertEqual(actual, expected) self.assertRaises(StopIteration, next, iterator) @@ -211,7 +211,7 @@ class RendertileSetTest(unittest.TestCase): """Test a round-robin post-traversal of the tree's dirty tiles""" # Expect the results in this proper order. iterator = iter(self.tree.posttraversal(robin=True)) - for expected, actual in izip(self.tile_paths_posttraversal_robin, iterator): + for expected, actual in zip(self.tile_paths_posttraversal_robin, iterator): self.assertEqual(actual, expected) self.assertRaises(StopIteration, next, iterator) diff --git a/test/test_settings.py b/test/test_settings.py index 3f44ec8..1b84d37 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -1,4 +1,5 @@ import unittest +from collections import OrderedDict from overviewer_core import configParser from overviewer_core.settingsValidators import ValidationException @@ -6,7 +7,6 @@ from overviewer_core.settingsValidators import ValidationException from overviewer_core import world from overviewer_core import rendermodes -from overviewer_core.util import OrderedDict class SettingsTest(unittest.TestCase): @@ -23,12 +23,12 @@ class SettingsTest(unittest.TestCase): # no exceptions so far. that's a good thing # Test the default - self.assertEquals(things['renders']['myworld']['bgcolor'], (26,26,26,0)) + self.assertEqual(things['renders']['myworld']['bgcolor'], (26,26,26,0)) # Test a non-default - self.assertEquals(things['renders']['otherworld']['bgcolor'], (255,255,255,0)) + self.assertEqual(things['renders']['otherworld']['bgcolor'], (255,255,255,0)) - self.assertEquals(things['renders']['myworld']['northdirection'], + self.assertEqual(things['renders']['myworld']['northdirection'], world.UPPER_LEFT) def test_rendermode_validation(self): @@ -63,7 +63,7 @@ class SettingsTest(unittest.TestCase): }), ])) self.s.set_config_item("outputdir", "/tmp/fictional/outputdir") - self.assertEquals(fromfile.get_validated_config(), self.s.get_validated_config()) + self.assertEqual(fromfile.get_validated_config(), self.s.get_validated_config()) def test_rendermode_string(self): self.s.set_config_item("worlds", { @@ -79,7 +79,7 @@ class SettingsTest(unittest.TestCase): }, }) p = self.s.get_validated_config() - self.assertEquals(p['renders']['myworld']['rendermode'], rendermodes.normal) + self.assertEqual(p['renders']['myworld']['rendermode'], rendermodes.normal) if __name__ == "__main__": unittest.main() diff --git a/test/test_tileset.py b/test/test_tileset.py index 5658d00..8adf8d8 100644 --- a/test/test_tileset.py +++ b/test/test_tileset.py @@ -50,11 +50,11 @@ class FakeRegionset(object): return NotImplementedError() def iterate_chunks(self): - for (x,z),mtime in self.chunks.iteritems(): + for (x,z),mtime in self.chunks.items(): yield x,z,mtime def iterate_newer_chunks(self, filemtime): - for (x,z),mtime in self.chunks.iteritems(): + for (x,z),mtime in self.chunks.items(): yield x,z,mtime def get_chunk_mtime(self, x, z): @@ -77,7 +77,7 @@ def get_tile_set(chunks): the compare_iterate_to_expected() method. """ tile_set = defaultdict(int) - for (chunkx, chunkz), chunkmtime in chunks.iteritems(): + for (chunkx, chunkz), chunkmtime in chunks.items(): col, row = tileset.convert_coords(chunkx, chunkz) @@ -86,9 +86,9 @@ def get_tile_set(chunks): tile_set[tile.path] = max(tile_set[tile.path], chunkmtime) # At this point, tile_set holds all the render-tiles - for tile, tile_mtime in tile_set.copy().iteritems(): + for tile, tile_mtime in tile_set.copy().items(): # All render-tiles are length 5. Hard-code its upper tiles - for i in reversed(xrange(5)): + for i in reversed(range(5)): tile_set[tile[:i]] = max(tile_set[tile[:i]], tile_mtime) return dict(tile_set) @@ -98,7 +98,7 @@ def create_fakedir(outputdir, tiles): files) and sets mtimes appropriately """ - for tilepath, tilemtime in tiles.iteritems(): + for tilepath, tilemtime in tiles.items(): dirpath = os.path.join(outputdir, *(str(x) for x in tilepath[:-1])) if len(tilepath) == 0: imgname = "base.png" @@ -175,7 +175,7 @@ class TilesetTest(unittest.TestCase): self.assertTrue(tilepath in expected, "%s was not expected to be returned. Expected %s" % (tilepath, expected)) # Now check that all expected tiles were indeed returned - for tilepath in expected.iterkeys(): + for tilepath in expected.keys(): self.assertTrue(tilepath in paths, "%s was expected to be returned but wasn't: %s" % (tilepath, paths)) def test_get_phase_length(self): @@ -215,7 +215,7 @@ class TilesetTest(unittest.TestCase): """Same as above but with a different set of chunks """ # Pick 3 random chunks to update - chunks = self.rs.chunks.keys() + chunks = list(self.rs.chunks.keys()) self.r.shuffle(chunks) updated_chunks = {} for key in chunks[:3]: diff --git a/test/test_world.py b/test/test_world.py index 8ef0231..0e7a0a9 100644 --- a/test/test_world.py +++ b/test/test_world.py @@ -17,19 +17,19 @@ class ExampleWorldTest(unittest.TestCase): w = world.World("test/data/worlds/exmaple") regionsets = w.get_regionsets() - self.assertEquals(len(regionsets), 3) + self.assertEqual(len(regionsets), 3) regionset = regionsets[0] - self.assertEquals(regionset.get_region_path(0,0), 'test/data/worlds/exmaple/DIM-1/region/r.0.0.mcr') - self.assertEquals(regionset.get_region_path(-1,0), 'test/data/worlds/exmaple/DIM-1/region/r.-1.0.mcr') - self.assertEquals(regionset.get_region_path(1,1), 'test/data/worlds/exmaple/DIM-1/region/r.0.0.mcr') - self.assertEquals(regionset.get_region_path(35,35), None) + self.assertEqual(regionset.get_region_path(0,0), 'test/data/worlds/exmaple/DIM-1/region/r.0.0.mcr') + self.assertEqual(regionset.get_region_path(-1,0), 'test/data/worlds/exmaple/DIM-1/region/r.-1.0.mcr') + self.assertEqual(regionset.get_region_path(1,1), 'test/data/worlds/exmaple/DIM-1/region/r.0.0.mcr') + self.assertEqual(regionset.get_region_path(35,35), None) # a few random chunks. reference timestamps fetched with libredstone - self.assertEquals(regionset.get_chunk_mtime(0,0), 1316728885) - self.assertEquals(regionset.get_chunk_mtime(-1,-1), 1316728886) - self.assertEquals(regionset.get_chunk_mtime(5,0), 1316728905) - self.assertEquals(regionset.get_chunk_mtime(-22,16), 1316786786) + self.assertEqual(regionset.get_chunk_mtime(0,0), 1316728885) + self.assertEqual(regionset.get_chunk_mtime(-1,-1), 1316728886) + self.assertEqual(regionset.get_chunk_mtime(5,0), 1316728905) + self.assertEqual(regionset.get_chunk_mtime(-22,16), 1316786786)