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