From 6c34cb40ed3ef34f55653d90ed4972e79131ba80 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 24 Aug 2016 20:37:11 +0200 Subject: [PATCH] Update pypath_to_abspath to make batchfile file lookups much more reliable. This is done as part of the batchprocess refactor #939. --- evennia/commands/default/batchprocess.py | 8 ++-- evennia/utils/batchprocessors.py | 10 ++-- evennia/utils/utils.py | 58 +++++++++++++++++------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/evennia/commands/default/batchprocess.py b/evennia/commands/default/batchprocess.py index 1a0f74e9b3..22b9d9333c 100644 --- a/evennia/commands/default/batchprocess.py +++ b/evennia/commands/default/batchprocess.py @@ -246,8 +246,8 @@ class CmdBatchCommands(COMMAND_DEFAULT_CLASS): caller.msg(_UTF8_ERROR % (python_path, err)) return except IOError as err: - string = "'%s' not found.\nYou have to supply the python path " - string += "of the file relative to \none of your batch-file directories (%s)." + string = "'%s' not found.\nYou have to supply the python path\n" \ + "using one of the defined batch-file directories\n (%s)." caller.msg(string % (python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) return if not commands: @@ -353,8 +353,8 @@ class CmdBatchCode(COMMAND_DEFAULT_CLASS): caller.msg(_UTF8_ERROR % (python_path, err)) return except IOError: - string = "'%s' not found.\nYou have to supply the python path " - string += "of the file relative to \nyour batch-file directories (%s)." + string = "'%s' not found.\nYou have to supply the python path\n" \ + "from one of the defined batch-file directories\n (%s)." caller.msg(string % (python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) return if not codes: diff --git a/evennia/utils/batchprocessors.py b/evennia/utils/batchprocessors.py index 540c006d8e..8b721d0e85 100644 --- a/evennia/utils/batchprocessors.py +++ b/evennia/utils/batchprocessors.py @@ -209,13 +209,9 @@ def read_batchfile(pythonpath, file_ending='.py'): """ - # open the file - abspaths = [] - for basepath in settings.BASE_BATCHPROCESS_PATHS: - # note that pypath_to_realpath has already checked the file for existence - if basepath.startswith("evennia"): - basepath = basepath.split("evennia", 1)[-1] - abspaths.extend(utils.pypath_to_realpath("%s.%s" % (basepath, pythonpath), file_ending)) + # find all possible absolute paths + abspaths = utils.pypath_to_realpath(pythonpath, + file_ending, settings.BASE_BATCHPROCESS_PATHS) if not abspaths: raise IOError text = None diff --git a/evennia/utils/utils.py b/evennia/utils/utils.py index 1e9c0c48a1..1593f3a2f4 100644 --- a/evennia/utils/utils.py +++ b/evennia/utils/utils.py @@ -18,6 +18,7 @@ import math import re import textwrap import random +from os.path import join as osjoin from importlib import import_module from inspect import ismodule, trace, getmembers, getmodule from collections import defaultdict, OrderedDict @@ -28,6 +29,8 @@ from django.utils.translation import ugettext as _ from evennia.utils import logger _MULTIMATCH_SEPARATOR = settings.SEARCH_MULTIMATCH_SEPARATOR +_EVENNIA_DIR = settings.EVENNIA_DIR +_GAME_DIR = settings.GAME_DIR try: import cPickle as pickle @@ -409,31 +412,52 @@ def get_evennia_version(): return evennia.__version__ -def pypath_to_realpath(python_path, file_ending='.py'): +def pypath_to_realpath(python_path, file_ending='.py', pypath_prefixes=None): """ Converts a dotted Python path to an absolute path under the Evennia library directory or under the current game directory. Args: - python_path (str): a dot-python path - file_ending (str): a file ending, including the period. + python_path (str): A dot-python path + file_ending (str): A file ending, including the period. + pypath_prefixes (list): A list of paths to test for existence. These + should be on python.path form. EVENNIA_DIR and GAME_DIR are automatically + checked, they need not be added to this list. Returns: - abspaths (list of str): The two absolute paths created by prepending - `EVENNIA_DIR` and `GAME_DIR` respectively. These are checked for - existence before being returned, so this may be an empty list. + abspaths (list): All existing, absolute paths created by + converting `python_path` to an absolute paths and/or + prepending `python_path` by `settings.EVENNIA_DIR`, + `settings.GAME_DIR` and by`pypath_prefixes` respectively. + + Notes: + This will also try a few combinations of paths to allow cases + where pypath is given including the "evennia." or "mygame." + prefixes. """ - pathsplit = python_path.strip().split('.') - paths = [os.path.join(settings.EVENNIA_DIR, *pathsplit), - os.path.join(settings.GAME_DIR, *pathsplit)] - if file_ending: - # attach file ending to the paths if not already set (a common mistake) - file_ending = ".%s" % file_ending if not file_ending.startswith(".") else file_ending - paths = ["%s%s" % (p, file_ending) if not p.endswith(file_ending) else p - for p in paths] - # check so the paths actually exists before returning - return [p for p in paths if os.path.isfile(p)] + path = python_path.strip().split('.') + plong = osjoin(*path) + file_ending + pshort = osjoin(*path[1:]) + file_ending if len(path) > 1 else plong # in case we had evennia. or mygame. + prefixlong = [osjoin(*ppath.strip().split('.')) + for ppath in make_iter(pypath_prefixes)] \ + if pypath_prefixes else [] + prefixshort = [osjoin(*ppath.strip().split('.')[1:]) + for ppath in make_iter(pypath_prefixes) if len(ppath.strip().split('.')) > 1] \ + if pypath_prefixes else [] + paths = [plong] + \ + [osjoin(_EVENNIA_DIR, prefix, plong) for prefix in prefixlong] + \ + [osjoin(_GAME_DIR, prefix, plong) for prefix in prefixlong] + \ + [osjoin(_EVENNIA_DIR, prefix, plong) for prefix in prefixshort] + \ + [osjoin(_GAME_DIR, prefix, plong) for prefix in prefixshort] + \ + [osjoin(_EVENNIA_DIR, plong), osjoin(_GAME_DIR, plong)] + \ + [osjoin(_EVENNIA_DIR, prefix, pshort) for prefix in prefixshort] + \ + [osjoin(_GAME_DIR, prefix, pshort) for prefix in prefixshort] + \ + [osjoin(_EVENNIA_DIR, prefix, pshort) for prefix in prefixlong] + \ + [osjoin(_GAME_DIR, prefix, pshort) for prefix in prefixlong] + \ + [osjoin(_EVENNIA_DIR, pshort), osjoin(_GAME_DIR, pshort)] + # filter out non-existing paths + return list(set(p for p in paths if os.path.isfile(p))) def dbref(dbref, reqhash=True): @@ -441,7 +465,7 @@ def dbref(dbref, reqhash=True): Converts/checks if input is a valid dbref. Args: - dbref (int or str): A datbase ref on the form N or #N. + dbref (int or str): A database ref on the form N or #N. reqhash (bool, optional): Require the #N form to accept input as a valid dbref.