Show More
@@ -1941,6 +1941,25 b' static void module_init(PyObject *mod)' | |||||
1941 | dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1); |
|
1941 | dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1); | |
1942 | } |
|
1942 | } | |
1943 |
|
1943 | |||
|
1944 | static int check_python_version() | |||
|
1945 | { | |||
|
1946 | PyObject *sys = PyImport_ImportModule("sys"); | |||
|
1947 | PyObject *hexversion = PyObject_GetAttrString(sys, "hexversion"); | |||
|
1948 | long version = PyInt_AsLong(hexversion); | |||
|
1949 | /* sys.hexversion is a 32-bit number by default, so the -1 case | |||
|
1950 | * should only occur in unusual circumstances (e.g. if sys.hexversion | |||
|
1951 | * is manually set to an invalid value). */ | |||
|
1952 | if ((version == -1) || (version >> 16 != PY_VERSION_HEX >> 16)) { | |||
|
1953 | PyErr_Format(PyExc_ImportError, "Python minor version mismatch: " | |||
|
1954 | "The Mercurial extension modules were compiled with Python " | |||
|
1955 | PY_VERSION ", but Mercurial is currently using Python with " | |||
|
1956 | "sys.hexversion=%ld: Python %s\n at: %s", version, | |||
|
1957 | Py_GetVersion(), Py_GetProgramFullPath()); | |||
|
1958 | return -1; | |||
|
1959 | } | |||
|
1960 | return 0; | |||
|
1961 | } | |||
|
1962 | ||||
1944 | #ifdef IS_PY3K |
|
1963 | #ifdef IS_PY3K | |
1945 | static struct PyModuleDef parsers_module = { |
|
1964 | static struct PyModuleDef parsers_module = { | |
1946 | PyModuleDef_HEAD_INIT, |
|
1965 | PyModuleDef_HEAD_INIT, | |
@@ -1952,6 +1971,8 b' static struct PyModuleDef parsers_module' | |||||
1952 |
|
1971 | |||
1953 | PyMODINIT_FUNC PyInit_parsers(void) |
|
1972 | PyMODINIT_FUNC PyInit_parsers(void) | |
1954 | { |
|
1973 | { | |
|
1974 | if (check_python_version() == -1) | |||
|
1975 | return; | |||
1955 | PyObject *mod = PyModule_Create(&parsers_module); |
|
1976 | PyObject *mod = PyModule_Create(&parsers_module); | |
1956 | module_init(mod); |
|
1977 | module_init(mod); | |
1957 | return mod; |
|
1978 | return mod; | |
@@ -1959,6 +1980,8 b' PyMODINIT_FUNC PyInit_parsers(void)' | |||||
1959 | #else |
|
1980 | #else | |
1960 | PyMODINIT_FUNC initparsers(void) |
|
1981 | PyMODINIT_FUNC initparsers(void) | |
1961 | { |
|
1982 | { | |
|
1983 | if (check_python_version() == -1) | |||
|
1984 | return; | |||
1962 | PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc); |
|
1985 | PyObject *mod = Py_InitModule3("parsers", methods, parsers_doc); | |
1963 | module_init(mod); |
|
1986 | module_init(mod); | |
1964 | } |
|
1987 | } |
@@ -1,6 +1,8 b'' | |||||
1 | from mercurial import parsers |
|
1 | from mercurial import parsers | |
2 | from mercurial.node import nullid, nullrev |
|
2 | from mercurial.node import nullid, nullrev | |
3 | import struct |
|
3 | import struct | |
|
4 | import subprocess | |||
|
5 | import sys | |||
4 |
|
6 | |||
5 | # This unit test compares the return value of the original Python |
|
7 | # This unit test compares the return value of the original Python | |
6 | # implementation of parseindex and the new C implementation for |
|
8 | # implementation of parseindex and the new C implementation for | |
@@ -97,7 +99,62 b' def parse_index2(data, inline):' | |||||
97 | index, chunkcache = parsers.parse_index2(data, inline) |
|
99 | index, chunkcache = parsers.parse_index2(data, inline) | |
98 | return list(index), chunkcache |
|
100 | return list(index), chunkcache | |
99 |
|
101 | |||
|
102 | def importparsers(hexversion): | |||
|
103 | """Import mercurial.parsers with the given sys.hexversion.""" | |||
|
104 | # The file parsers.c inspects sys.hexversion to determine the version | |||
|
105 | # of the currently-running Python interpreter, so we monkey-patch | |||
|
106 | # sys.hexversion to simulate using different versions. | |||
|
107 | code = ("import sys; sys.hexversion=%s; " | |||
|
108 | "import mercurial.parsers" % hexversion) | |||
|
109 | cmd = "python -c \"%s\"" % code | |||
|
110 | # We need to do these tests inside a subprocess because parser.c's | |||
|
111 | # version-checking code happens inside the module init function, and | |||
|
112 | # when using reload() to reimport an extension module, "The init function | |||
|
113 | # of extension modules is not called a second time" | |||
|
114 | # (from http://docs.python.org/2/library/functions.html?#reload). | |||
|
115 | p = subprocess.Popen(cmd, shell=True, | |||
|
116 | stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | |||
|
117 | return p.communicate() # returns stdout, stderr | |||
|
118 | ||||
|
119 | def printhexfail(testnumber, hexversion, msg): | |||
|
120 | try: | |||
|
121 | hexstring = hex(hexversion) | |||
|
122 | except TypeError: | |||
|
123 | hexstring = None | |||
|
124 | print ("%s) using Python %s and patched sys.hexversion %r (%r): %s" % | |||
|
125 | (testnumber, sys.version_info, hexversion, hexstring, msg)) | |||
|
126 | ||||
|
127 | def testversionokay(testnumber, hexversion): | |||
|
128 | stdout, stderr = importparsers(hexversion) | |||
|
129 | if stdout: | |||
|
130 | printhexfail(testnumber, hexversion, | |||
|
131 | "Expected no stdout but got: %r" % stdout) | |||
|
132 | ||||
|
133 | def testversionfail(testnumber, hexversion): | |||
|
134 | stdout, stderr = importparsers(hexversion) | |||
|
135 | if not "ImportError: Python minor version mismatch" in stdout: | |||
|
136 | printhexfail(testnumber, hexversion, | |||
|
137 | "Expected stdout to contain %r but got: %r" % | |||
|
138 | (errstring, stdout)) | |||
|
139 | ||||
|
140 | def makehex(major, minor, micro): | |||
|
141 | return int("%x%02x%02x00" % (major, minor, micro), 16) | |||
|
142 | ||||
|
143 | def runversiontests(): | |||
|
144 | """Test importing parsers using different Python versions.""" | |||
|
145 | info = sys.version_info | |||
|
146 | major, minor, micro = info[0], info[1], info[2] | |||
|
147 | # Test same major-minor versions. | |||
|
148 | testversionokay(1, makehex(major, minor, micro)) | |||
|
149 | testversionokay(2, makehex(major, minor, micro + 1)) | |||
|
150 | # Test different major-minor versions. | |||
|
151 | testversionfail(3, makehex(major + 1, minor, micro)) | |||
|
152 | testversionfail(4, makehex(major, minor + 1, micro)) | |||
|
153 | testversionfail(5, "'foo'") | |||
|
154 | ||||
100 | def runtest() : |
|
155 | def runtest() : | |
|
156 | runversiontests() | |||
|
157 | ||||
101 | # Check that parse_index2() raises TypeError on bad arguments. |
|
158 | # Check that parse_index2() raises TypeError on bad arguments. | |
102 | try: |
|
159 | try: | |
103 | parse_index2(0, True) |
|
160 | parse_index2(0, True) |
General Comments 0
You need to be logged in to leave comments.
Login now