1# Copyright 2004-2021 Tom Rothamel <pytom@bishoujo.us> 2# 3# Permission is hereby granted, free of charge, to any person 4# obtaining a copy of this software and associated documentation files 5# (the "Software"), to deal in the Software without restriction, 6# including without limitation the rights to use, copy, modify, merge, 7# publish, distribute, sublicense, and/or sell copies of the Software, 8# and to permit persons to whom the Software is furnished to do so, 9# subject to the following conditions: 10# 11# The above copyright notice and this permission notice shall be 12# included in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22""" 23This module is defined to allow us to program in Python 2 with a high degree 24of compatibility with Python 3, and vice versa. It's intended to be invoked 25with the following preamble:: 26 27 from __future__ import division, absolute_import, with_statement, print_function, unicode_literals 28 from renpy.compat import * 29 30Right now, it does the following things: 31 32* Sets up aliases for Python 3 module moves, allowing the Python 3 names 33 to be used in Python 2. 34 35* Defines PY2 in the current context, to make Python 2 conditional. 36 37* Aliases pickle to cPickle on Python 3, to support Python 2 code 38 choosing between the implementations, where the choice is meaningful 39 40* Replaces open with a function that mimics the Python 3 behavior, of 41 opening files in a unicode-friendly mode by default. 42 43* Redefines the text types, so that str is always the unicode type, and 44 basestring is the list of string types available on the system. 45 46* Exposes bchr, bord, and tobytes from future.utils. 47 48* Changes the meaning of the .items(), .keys(), and .values() methods of 49 dict to return views, rather than lists. (This is a fairly major change, 50 and so is only available when with_statement and division are both 51 imported. 52 53* Aliases xrange to range on Python 2. 54 55""" 56 57from __future__ import division, absolute_import, with_statement, print_function, unicode_literals 58 59import future.standard_library 60import future.utils 61import builtins 62 63import io 64import sys 65import operator 66 67python_open = open 68 69################################################################################ 70# Alias the Python 3 standard library. 71 72future.standard_library.install_aliases() 73 74################################################################################ 75# Determine if this is Python2. 76 77PY2 = future.utils.PY2 78 79################################################################################ 80# Make open mimic Python 3. 81 82if PY2: 83 open = io.open 84 import re 85 re.Pattern = re._pattern_type 86else: 87 open = builtins.open 88 89 90def compat_open(*args, **kwargs): 91 if (sys._getframe(1).f_code.co_flags & 0xa000) == 0xa000: 92 return open(*args, **kwargs) 93 else: 94 return python_open(*args, **kwargs) 95 96 97################################################################################ 98# Make strict use surrogateescape error handling. 99if PY2: 100 import codecs 101 102 strict_error = codecs.lookup_error("strict") 103 codecs.register_error("python_strict", strict_error) 104 surrogateescape_error = codecs.lookup_error("surrogateescape") 105 codecs.register_error("strict", surrogateescape_error) 106 107import renpy 108renpy.update_path() 109 110################################################################################ 111# String (text and binary) types and functions. 112 113basestring = future.utils.string_types # @ReservedAssignment 114pystr = str 115str = future.utils.text_type # @ReservedAssignment 116unicode = future.utils.text_type # @ReservedAssignment 117 118bord = future.utils.bord 119bchr = future.utils.bchr 120tobytes = future.utils.tobytes 121 122from future.builtins import chr 123 124################################################################################ 125# Dictionary views. 126 127# The try block solves a chicken-and-egg problem when dictviews is not 128# compiled yet, as part of the Ren'Py build process. 129try: 130 if PY2: 131 import renpy.compat.dictviews # @UnresolvedImport 132except ImportError: 133 import sys 134 print("Could not import renpy.compat.dictviews.", file=sys.stderr) 135 136################################################################################ 137# Range. 138 139if PY2: 140 range = xrange # @ReservedAssignment 141else: 142 range = builtins.range 143 144################################################################################ 145# Sort key functions. 146 147__all__ = [ "PY2", "open", "basestring", "str", "pystr", "range", 148 "bord", "bchr", "tobytes", "chr", "unicode", ] 149 150if PY2: 151 __all__ = [ bytes(i) for i in __all__ ] 152