1#!/usr/bin/env python 2# -*- mode: python; coding: utf-8; -*- 3# ---------------------------------------------------------------------------## 4# 5# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer 6# Copyright (C) 2003 Mt. Hood Playing Card Co. 7# Copyright (C) 2005-2009 Skomoroh 8# 9# This program is free software: you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation, either version 3 of the License, or 12# (at your option) any later version. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with this program. If not, see <http://www.gnu.org/licenses/>. 21# 22# ---------------------------------------------------------------------------## 23 24import locale 25import os 26import re 27import sys 28import time 29import webbrowser 30from pickle import Pickler, Unpickler 31 32from pysollib.settings import PACKAGE, TOOLKIT 33 34import six 35from six import print_ 36 37Image = ImageTk = ImageOps = None 38if TOOLKIT == 'tk': 39 try: # PIL 40 from PIL import Image 41 from PIL import ImageTk # noqa: F401 42 from PIL import ImageOps # noqa: F401 43 except ImportError: 44 Image = None 45 else: 46 # for py2exe 47 from PIL import GifImagePlugin # noqa: F401 48 from PIL import PngImagePlugin # noqa: F401 49 from PIL import JpegImagePlugin # noqa: F401 50 from PIL import BmpImagePlugin # noqa: F401 51 from PIL import PpmImagePlugin # noqa: F401 52 Image._initialized = 2 53USE_PIL = False 54if TOOLKIT == 'tk' and Image: 55 USE_PIL = True 56 57# debug 58# Image = None 59# USE_PIL = False 60 61# ************************************************************************ 62# * exceptions 63# ************************************************************************ 64 65 66class SubclassResponsibility(Exception): 67 pass 68 69 70# ************************************************************************ 71# * misc. util 72# ************************************************************************ 73 74 75def latin1_to_ascii(n): 76 if sys.version_info > (3,): 77 return n 78 # return n 79 n = n.encode('iso8859-1', 'replace') 80 # FIXME: rewrite this for better speed 81 return (n.replace("\xc4", "Ae") 82 .replace("\xd6", "Oe") 83 .replace("\xdc", "Ue") 84 .replace("\xe4", "ae") 85 .replace("\xf6", "oe") 86 .replace("\xfc", "ue")) 87 88 89def latin1_normalize(n): 90 normal = re.sub(r"[^\w]", "", latin1_to_ascii(n).lower()) 91 # Some game names end in a +, and would have the same normalized 92 # name as their counterpart. This is a failsafe to avoid duplicate 93 # name conflicts. Though there is probably a better way to do this. 94 if n.endswith("+"): 95 normal += "plus" 96 return normal 97 98 99def format_time(t): 100 # print 'format_time:', t 101 if t <= 0: 102 return "0:00" 103 if t < 3600: 104 return "%d:%02d" % (t // 60, t % 60) 105 return "%d:%02d:%02d" % (t // 3600, (t % 3600) // 60, t % 60) 106 107 108def print_err(s, level=1): 109 if level == 0: 110 ss = PACKAGE+': ERROR:' 111 elif level == 1: 112 ss = PACKAGE+': WARNING:' 113 elif level == 2: 114 ss = PACKAGE+': DEBUG WARNING:' 115 try: 116 print_(ss, s, file=sys.stderr) 117 except Exception: 118 print_(ss, s.encode(locale.getpreferredencoding()), file=sys.stderr) 119 sys.stderr.flush() 120 121 122# ************************************************************************ 123# * misc. portab stuff 124# ************************************************************************ 125 126def getusername(): 127 if os.name == "nt": 128 return win32_getusername() 129 user = os.environ.get("USER", "").strip() 130 if not user: 131 user = os.environ.get("LOGNAME", "").strip() 132 return user 133 134 135def getprefdir(package): 136 137 if (TOOLKIT == 'kivy'): 138 from pysollib.kivy.LApp import get_platform 139 plat = get_platform() 140 if plat == 'android': 141 os.environ['HOME'] = '/sdcard' 142 143 if os.name == "nt": 144 return win32_getprefdir(package) 145 home = os.environ.get("HOME", "").strip() 146 if not home or not os.path.isdir(home): 147 home = os.curdir 148 return os.path.join(home, ".PySolFC") 149 150 151# high resolution clock() and sleep() 152try: 153 uclock = time.perf_counter 154except Exception: 155 uclock = time.clock 156 157usleep = time.sleep 158if os.name == "posix": 159 uclock = time.time 160 161# ************************************************************************ 162# * MSWin util 163# ************************************************************************ 164 165 166def win32_getusername(): 167 user = os.environ.get('USERNAME', '').strip() 168 try: 169 user = six.text_type(user, locale.getpreferredencoding()) 170 except Exception: 171 user = '' 172 return user 173 174 175def win32_getprefdir(package): 176 portprefdir = 'config' # portable varsion 177 if os.path.isdir(portprefdir): 178 return portprefdir 179 # %USERPROFILE%, %APPDATA% 180 hd = os.environ.get('APPDATA') 181 if not hd: 182 hd = os.path.expanduser('~') 183 if hd == '~': # win9x 184 hd = os.path.abspath('/windows/Application Data') 185 if not os.path.exists(hd): 186 hd = os.path.abspath('/') 187 return os.path.join(hd, 'PySolFC') 188 189 190# ************************************************************************ 191# * memory util 192# ************************************************************************ 193 194def destruct(obj): 195 if TOOLKIT == 'kivy': 196 return 197 198 # assist in breaking circular references 199 if obj is not None: 200 for k in obj.__dict__.keys(): 201 obj.__dict__[k] = None 202 # del obj.__dict__[k] 203 204 205# ************************************************************************ 206# * 207# ************************************************************************ 208 209class Struct: 210 def __init__(self, **kw): 211 self.__dict__.update(kw) 212 213 def __str__(self): 214 return str(self.__dict__) 215 216 def __setattr__(self, key, value): 217 if key not in self.__dict__: 218 raise AttributeError(key) 219 self.__dict__[key] = value 220 221 def addattr(self, **kw): 222 for key in kw.keys(): 223 if hasattr(self, key): 224 raise AttributeError(key) 225 self.__dict__.update(kw) 226 227 def update(self, dict): 228 for key in dict.keys(): 229 if key not in self.__dict__: 230 raise AttributeError(key) 231 self.__dict__.update(dict) 232 233 def clear(self): 234 for key in self.__dict__.keys(): 235 if isinstance(key, list): 236 self.__dict__[key] = [] 237 elif isinstance(key, tuple): 238 self.__dict__[key] = () 239 elif isinstance(key, dict): 240 self.__dict__[key] = {} 241 else: 242 self.__dict__[key] = None 243 244 def copy(self): 245 c = self.__class__() 246 c.__dict__.update(self.__dict__) 247 return c 248 249 250# ************************************************************************ 251# * keyword argument util 252# ************************************************************************ 253 254# update keyword arguments with default arguments 255def kwdefault(kw, **defaults): 256 for k, v in defaults.items(): 257 if k not in kw: 258 kw[k] = v 259 260 261class KwStruct: 262 def __init__(self, kw={}, **defaults): 263 if isinstance(kw, KwStruct): 264 kw = kw.__dict__ 265 if isinstance(defaults, KwStruct): 266 defaults = defaults.__dict__ 267 if defaults: 268 kw = kw.copy() 269 for k, v in defaults.items(): 270 if k not in kw: 271 kw[k] = v 272 self.__dict__.update(kw) 273 274 def __setattr__(self, key, value): 275 if key not in self.__dict__: 276 raise AttributeError(key) 277 self.__dict__[key] = value 278 279 def __getitem__(self, key): 280 return getattr(self, key) 281 282 def get(self, key, default=None): 283 return self.__dict__.get(key, default) 284 285 def getKw(self): 286 return self.__dict__ 287 288 289# ************************************************************************ 290# * pickling support 291# ************************************************************************ 292 293def pickle(obj, filename, protocol=0): 294 try: 295 with open(filename, "wb") as fh: 296 Pickler(fh, protocol).dump(obj) 297 # print "Pickled", filename 298 finally: 299 pass 300 301 302def unpickle(filename): 303 obj = None 304 try: 305 with open(filename, "rb") as fh: 306 x = Unpickler(fh).load() 307 obj = x 308 # print "Unpickled", filename 309 finally: 310 pass 311 return obj 312 313 314# ************************************************************************ 315# * 316# ************************************************************************ 317 318def openURL(url): 319 try: 320 webbrowser.open(url) 321 except OSError: # raised on windows if link is unreadable 322 pass 323 except Exception: 324 return False 325 return True 326