all-changes.patch 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. --- contrib/tools/cython/Cython/Compiler/Annotate.py (index)
  2. +++ contrib/tools/cython/Cython/Compiler/Annotate.py (working tree)
  3. @@ -10,7 +10,10 @@ import textwrap
  4. from datetime import datetime
  5. from functools import partial
  6. from collections import defaultdict
  7. -from xml.sax.saxutils import escape as html_escape
  8. +try:
  9. + from xml.sax.saxutils import escape as html_escape
  10. +except ImportError:
  11. + pass
  12. try:
  13. from StringIO import StringIO
  14. except ImportError:
  15. --- contrib/tools/cython/Cython/Compiler/CmdLine.py (index)
  16. +++ contrib/tools/cython/Cython/Compiler/CmdLine.py (working tree)
  17. @@ -152,6 +152,10 @@ def parse_command_line(args):
  18. elif option == "--lenient":
  19. Options.error_on_unknown_names = False
  20. Options.error_on_uninitialized = False
  21. + elif option == '--init-suffix':
  22. + options.init_suffix = pop_arg()
  23. + elif option == '--source-root':
  24. + Options.source_root = pop_arg()
  25. elif option == '-2':
  26. options.language_level = 2
  27. elif option == '-3':
  28. --- contrib/tools/cython/Cython/Compiler/ExprNodes.py (index)
  29. +++ contrib/tools/cython/Cython/Compiler/ExprNodes.py (working tree)
  30. @@ -9543,6 +9543,8 @@ class CodeObjectNode(ExprNode):
  31. func.name, identifier=True, is_str=False, unicode_value=func.name)
  32. # FIXME: better way to get the module file path at module init time? Encoding to use?
  33. file_path = StringEncoding.bytes_literal(func.pos[0].get_filenametable_entry().encode('utf8'), 'utf8')
  34. + # XXX Use get_description() to set arcadia root relative filename
  35. + file_path = StringEncoding.bytes_literal(func.pos[0].get_description().encode('utf8'), 'utf8')
  36. file_path_const = code.get_py_string_const(file_path, identifier=False, is_str=True)
  37. # This combination makes CPython create a new dict for "frame.f_locals" (see GH #1836).
  38. --- contrib/tools/cython/Cython/Compiler/Main.py (index)
  39. +++ contrib/tools/cython/Cython/Compiler/Main.py (working tree)
  40. @@ -206,9 +206,7 @@ class Context(object):
  41. if not pxd_pathname:
  42. if debug_find_module:
  43. print("...looking for pxd file")
  44. - # Only look in sys.path if we are explicitly looking
  45. - # for a .pxd file.
  46. - pxd_pathname = self.find_pxd_file(qualified_name, pos, sys_path=need_pxd)
  47. + pxd_pathname = self.find_pxd_file(qualified_name, pos)
  48. if debug_find_module:
  49. print("......found %s" % pxd_pathname)
  50. if not pxd_pathname and need_pxd:
  51. @@ -228,6 +226,8 @@ class Context(object):
  52. rel_path = module_name.replace('.', os.sep) + os.path.splitext(pxd_pathname)[1]
  53. if not pxd_pathname.endswith(rel_path):
  54. rel_path = pxd_pathname # safety measure to prevent printing incorrect paths
  55. + if Options.source_root:
  56. + rel_path = os.path.relpath(pxd_pathname, Options.source_root)
  57. source_desc = FileSourceDescriptor(pxd_pathname, rel_path)
  58. err, result = self.process_pxd(source_desc, scope, qualified_name)
  59. if err:
  60. @@ -238,7 +238,7 @@ class Context(object):
  61. pass
  62. return scope
  63. - def find_pxd_file(self, qualified_name, pos, sys_path=True):
  64. + def find_pxd_file(self, qualified_name, pos, sys_path=False):
  65. # Search include path (and sys.path if sys_path is True) for
  66. # the .pxd file corresponding to the given fully-qualified
  67. # module name.
  68. @@ -481,7 +481,7 @@ def run_pipeline(source, options, full_module_name=None, context=None):
  69. # Set up source object
  70. cwd = os.getcwd()
  71. abs_path = os.path.abspath(source)
  72. - full_module_name = full_module_name or context.extract_module_name(source, options)
  73. + full_module_name = full_module_name or options.module_name or context.extract_module_name(source, options)
  74. Utils.raise_error_if_module_name_forbidden(full_module_name)
  75. @@ -491,6 +491,8 @@ def run_pipeline(source, options, full_module_name=None, context=None):
  76. rel_path = source # safety measure to prevent printing incorrect paths
  77. else:
  78. rel_path = abs_path
  79. + if Options.source_root:
  80. + rel_path = os.path.relpath(abs_path, Options.source_root)
  81. source_desc = FileSourceDescriptor(abs_path, rel_path)
  82. source = CompilationSource(source_desc, full_module_name, cwd)
  83. @@ -835,6 +837,21 @@ def search_include_directories(dirs, qualified_name, suffix, pos, include=False)
  84. package_filename)
  85. if os.path.exists(path):
  86. return path
  87. +
  88. + # Arcadia-specific lookup: search for packages in include paths,
  89. + # ignoring existence of __init__.py files as packages markers
  90. + # (they are not required by Arcadia build system)
  91. + if not include:
  92. + for dir in dirs:
  93. + package_dir = os.path.join(dir, *package_names)
  94. + path = os.path.join(package_dir, module_filename)
  95. + if os.path.exists(path):
  96. + return path
  97. + path = os.path.join(dir, package_dir, module_name,
  98. + package_filename)
  99. + if os.path.exists(path):
  100. + return path
  101. +
  102. return None
  103. @@ -903,6 +920,7 @@ default_options = dict(
  104. language_level = None, # warn but default to 2
  105. formal_grammar = False,
  106. gdb_debug = False,
  107. + init_suffix = None,
  108. compile_time_env = None,
  109. common_utility_include_dir = None,
  110. output_dir=None,
  111. --- contrib/tools/cython/Cython/Compiler/ModuleNode.py (index)
  112. +++ contrib/tools/cython/Cython/Compiler/ModuleNode.py (working tree)
  113. @@ -208,9 +208,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  114. h_code.putln("/* It now returns a PyModuleDef instance instead of a PyModule instance. */")
  115. h_code.putln("")
  116. h_code.putln("#if PY_MAJOR_VERSION < 3")
  117. - h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
  118. + init_name = 'init' + (options.init_suffix or env.module_name)
  119. + h_code.putln("PyMODINIT_FUNC %s(void);" % init_name)
  120. h_code.putln("#else")
  121. - h_code.putln("PyMODINIT_FUNC %s(void);" % self.mod_init_func_cname('PyInit', env))
  122. + h_code.putln("PyMODINIT_FUNC %s(void);" % self.mod_init_func_cname('PyInit', env, options))
  123. h_code.putln("#endif")
  124. h_code.putln("")
  125. h_code.putln("#endif /* !%s */" % h_guard)
  126. @@ -389,13 +390,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  127. self.generate_method_table(env, code)
  128. if env.has_import_star:
  129. self.generate_import_star(env, code)
  130. - self.generate_pymoduledef_struct(env, code)
  131. + self.generate_pymoduledef_struct(env, options, code)
  132. # initialise the macro to reduce the code size of one-time functionality
  133. code.putln(UtilityCode.load_as_string("SmallCodeConfig", "ModuleSetupCode.c")[0].strip())
  134. # init_globals is inserted before this
  135. - self.generate_module_init_func(modules[:-1], env, globalstate['init_module'])
  136. + self.generate_module_init_func(modules[:-1], env, options, globalstate['init_module'])
  137. self.generate_module_cleanup_func(env, globalstate['cleanup_module'])
  138. if Options.embed:
  139. self.generate_main_method(env, globalstate['main_method'])
  140. @@ -782,6 +783,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  141. if code.globalstate.filename_list:
  142. for source_desc in code.globalstate.filename_list:
  143. file_path = source_desc.get_filenametable_entry()
  144. + if Options.source_root:
  145. + # If source root specified, dump description - it's source root relative filename
  146. + file_path = source_desc.get_description()
  147. if isabs(file_path):
  148. file_path = basename(file_path) # never include absolute paths
  149. escaped_filename = file_path.replace("\\", "\\\\").replace('"', r'\"')
  150. @@ -928,6 +932,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  151. constructor = None
  152. destructor = None
  153. for attr in scope.var_entries:
  154. + if attr.type.is_cfunction:
  155. + code.put("inline ")
  156. if attr.type.is_cfunction and attr.type.is_static_method:
  157. code.put("static ")
  158. elif attr.name == "<init>":
  159. @@ -2308,14 +2314,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  160. code.putln(UtilityCode.load_as_string("ImportStar", "ImportExport.c")[1])
  161. code.exit_cfunc_scope() # done with labels
  162. - def generate_module_init_func(self, imported_modules, env, code):
  163. + def generate_module_init_func(self, imported_modules, env, options, code):
  164. subfunction = self.mod_init_subfunction(self.pos, self.scope, code)
  165. code.enter_cfunc_scope(self.scope)
  166. code.putln("")
  167. code.putln(UtilityCode.load_as_string("PyModInitFuncType", "ModuleSetupCode.c")[0])
  168. - header2 = "__Pyx_PyMODINIT_FUNC init%s(void)" % env.module_name
  169. - header3 = "__Pyx_PyMODINIT_FUNC %s(void)" % self.mod_init_func_cname('PyInit', env)
  170. + init_name = 'init' + (options.init_suffix or env.module_name)
  171. + header2 = "__Pyx_PyMODINIT_FUNC %s(void)" % init_name
  172. + header3 = "__Pyx_PyMODINIT_FUNC %s(void)" % self.mod_init_func_cname('PyInit', env, options)
  173. code.putln("#if PY_MAJOR_VERSION < 3")
  174. # Optimise for small code size as the module init function is only executed once.
  175. code.putln("%s CYTHON_SMALL_CODE; /*proto*/" % header2)
  176. @@ -2412,7 +2419,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  177. code.putln("#endif")
  178. code.putln("/*--- Module creation code ---*/")
  179. - self.generate_module_creation_code(env, code)
  180. + self.generate_module_creation_code(env, options, code)
  181. code.putln("/*--- Initialize various global constants etc. ---*/")
  182. code.put_error_if_neg(self.pos, "__Pyx_InitGlobals()")
  183. @@ -2737,10 +2744,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  184. main_method=Options.embed,
  185. wmain_method=wmain))
  186. - def mod_init_func_cname(self, prefix, env):
  187. - return '%s_%s' % (prefix, env.module_name)
  188. + def mod_init_func_cname(self, prefix, env, options=None):
  189. + return '%s_%s' % (prefix, options and options.init_suffix or env.module_name)
  190. - def generate_pymoduledef_struct(self, env, code):
  191. + def generate_pymoduledef_struct(self, env, options, code):
  192. if env.doc:
  193. doc = "%s" % code.get_string_const(env.doc)
  194. else:
  195. @@ -2768,7 +2775,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  196. code.putln("")
  197. code.putln("static struct PyModuleDef %s = {" % Naming.pymoduledef_cname)
  198. code.putln(" PyModuleDef_HEAD_INIT,")
  199. - code.putln(' "%s",' % env.module_name)
  200. + code.putln(' "%s",' % (options.module_name or env.module_name))
  201. code.putln(" %s, /* m_doc */" % doc)
  202. code.putln("#if CYTHON_PEP489_MULTI_PHASE_INIT")
  203. code.putln(" 0, /* m_size */")
  204. @@ -2787,7 +2794,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  205. code.putln("};")
  206. code.putln("#endif")
  207. - def generate_module_creation_code(self, env, code):
  208. + def generate_module_creation_code(self, env, options, code):
  209. # Generate code to create the module object and
  210. # install the builtins.
  211. if env.doc:
  212. @@ -2805,7 +2812,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
  213. code.putln(
  214. '%s = Py_InitModule4("%s", %s, %s, 0, PYTHON_API_VERSION); Py_XINCREF(%s);' % (
  215. env.module_cname,
  216. - env.module_name,
  217. + options.module_name or env.module_name,
  218. env.method_table_cname,
  219. doc,
  220. env.module_cname))
  221. --- contrib/tools/cython/Cython/Compiler/Nodes.py (index)
  222. +++ contrib/tools/cython/Cython/Compiler/Nodes.py (working tree)
  223. @@ -4170,7 +4170,7 @@ class GeneratorBodyDefNode(DefNode):
  224. self.declare_generator_body(env)
  225. def generate_function_header(self, code, proto=False):
  226. - header = "static PyObject *%s(__pyx_CoroutineObject *%s, CYTHON_UNUSED PyThreadState *%s, PyObject *%s)" % (
  227. + header = "static PyObject *%s(PyObject *%s_obj, CYTHON_UNUSED PyThreadState *%s, PyObject *%s)" % (
  228. self.entry.func_cname,
  229. Naming.generator_cname,
  230. Naming.local_tstate_cname,
  231. @@ -4196,6 +4196,7 @@ class GeneratorBodyDefNode(DefNode):
  232. # ----- Function header
  233. code.putln("")
  234. self.generate_function_header(code)
  235. + code.putln("__pyx_CoroutineObject *%s = (__pyx_CoroutineObject *)%s_obj;" % (Naming.generator_cname, Naming.generator_cname))
  236. closure_init_code = code.insertion_point()
  237. # ----- Local variables
  238. code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
  239. --- contrib/tools/cython/Cython/Compiler/Options.py (index)
  240. +++ contrib/tools/cython/Cython/Compiler/Options.py (working tree)
  241. @@ -150,6 +150,9 @@ buffer_max_dims = 8
  242. #: Number of function closure instances to keep in a freelist (0: no freelists)
  243. closure_freelist_size = 8
  244. +# Arcadia specific
  245. +source_root = None
  246. +
  247. def get_directive_defaults():
  248. # To add an item to this list, all accesses should be changed to use the new
  249. --- contrib/tools/cython/Cython/Compiler/Parsing.py (index)
  250. +++ contrib/tools/cython/Cython/Compiler/Parsing.py (working tree)
  251. @@ -2046,7 +2046,12 @@ def p_include_statement(s, ctx):
  252. if include_file_path:
  253. s.included_files.append(include_file_name)
  254. with Utils.open_source_file(include_file_path) as f:
  255. - source_desc = FileSourceDescriptor(include_file_path)
  256. + if Options.source_root:
  257. + import os
  258. + rel_path = os.path.relpath(include_file_path, Options.source_root)
  259. + else:
  260. + rel_path = None
  261. + source_desc = FileSourceDescriptor(include_file_path, rel_path)
  262. s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments)
  263. tree = p_statement_list(s2, ctx)
  264. return tree
  265. @@ -3696,6 +3701,9 @@ def p_module(s, pxd, full_module_name, ctx=Ctx):
  266. s.parse_comments = False
  267. if s.context.language_level is None:
  268. + s.context.set_language_level(2) # Arcadia default.
  269. +
  270. + if s.context.language_level is None:
  271. s.context.set_language_level(2)
  272. if pos[0].filename:
  273. import warnings
  274. --- contrib/tools/cython/Cython/Compiler/PyrexTypes.py (index)
  275. +++ contrib/tools/cython/Cython/Compiler/PyrexTypes.py (working tree)
  276. @@ -3483,7 +3483,7 @@ class CStructOrUnionType(CType):
  277. return expr_code
  278. return super(CStructOrUnionType, self).cast_code(expr_code)
  279. -cpp_string_conversions = ("std::string",)
  280. +cpp_string_conversions = ("std::string", "TString", "TStringBuf")
  281. builtin_cpp_conversions = {
  282. # type element template params
  283. @@ -3495,6 +3495,11 @@ builtin_cpp_conversions = {
  284. "std::map": 2,
  285. "std::unordered_map": 2,
  286. "std::complex": 1,
  287. + # arcadia_cpp_conversions
  288. + "TMaybe": 1,
  289. + "TVector": 1,
  290. + "THashMap": 2,
  291. + "TMap": 2,
  292. }
  293. class CppClassType(CType):
  294. @@ -3524,7 +3529,7 @@ class CppClassType(CType):
  295. self.templates = templates
  296. self.template_type = template_type
  297. self.num_optional_templates = sum(is_optional_template_param(T) for T in templates or ())
  298. - if templates:
  299. + if templates and False: # https://github.com/cython/cython/issues/1868
  300. self.specializations = {tuple(zip(templates, templates)): self}
  301. else:
  302. self.specializations = {}
  303. @@ -3570,8 +3575,10 @@ class CppClassType(CType):
  304. if self.cname in cpp_string_conversions:
  305. cls = 'string'
  306. tags = type_identifier(self),
  307. - else:
  308. + elif self.cname.startswith('std::'):
  309. cls = self.cname[5:]
  310. + else:
  311. + cls = 'arcadia_' + self.cname
  312. cname = '__pyx_convert_%s_from_py_%s' % (cls, '__and_'.join(tags))
  313. context.update({
  314. 'cname': cname,
  315. @@ -3594,7 +3601,6 @@ class CppClassType(CType):
  316. return False
  317. return True
  318. -
  319. def create_to_py_utility_code(self, env):
  320. if self.to_py_function is not None:
  321. return True
  322. @@ -3614,9 +3620,12 @@ class CppClassType(CType):
  323. cls = 'string'
  324. prefix = 'PyObject_' # gets specialised by explicit type casts in CoerceToPyTypeNode
  325. tags = type_identifier(self),
  326. - else:
  327. + elif self.cname.startswith('std::'):
  328. cls = self.cname[5:]
  329. prefix = ''
  330. + else:
  331. + cls = 'arcadia_' + self.cname
  332. + prefix = ''
  333. cname = "__pyx_convert_%s%s_to_py_%s" % (prefix, cls, "____".join(tags))
  334. context.update({
  335. 'cname': cname,
  336. --- contrib/tools/cython/Cython/Compiler/Scanning.py (index)
  337. +++ contrib/tools/cython/Cython/Compiler/Scanning.py (working tree)
  338. @@ -245,6 +245,8 @@ class FileSourceDescriptor(SourceDescriptor):
  339. return lines
  340. def get_description(self):
  341. + # Dump path_description, it's already arcadia root relative (required for proper file matching in coverage)
  342. + return self.path_description
  343. try:
  344. return os.path.relpath(self.path_description)
  345. except ValueError:
  346. --- contrib/tools/cython/Cython/Coverage.py (index)
  347. +++ contrib/tools/cython/Cython/Coverage.py (working tree)
  348. @@ -65,10 +65,14 @@ class Plugin(CoveragePlugin):
  349. """
  350. Try to find a C source file for a file path found by the tracer.
  351. """
  352. + # TODO We need to pxd-files to the include map. For more info see pybuild.py
  353. + # Currently skip such files, because they are not supported in Arcadia pybuild with coverage.
  354. + if os.path.splitext(filename)[-1] not in ('.pyx', '.pxi'):
  355. + return None
  356. if filename.startswith('<') or filename.startswith('memory:'):
  357. return None
  358. c_file = py_file = None
  359. - filename = canonical_filename(os.path.abspath(filename))
  360. + filename = canonical_filename(filename)
  361. if self._c_files_map and filename in self._c_files_map:
  362. c_file = self._c_files_map[filename][0]
  363. @@ -98,16 +102,21 @@ class Plugin(CoveragePlugin):
  364. # from coverage.python import PythonFileReporter
  365. # return PythonFileReporter(filename)
  366. - filename = canonical_filename(os.path.abspath(filename))
  367. + filename = canonical_filename(filename)
  368. if self._c_files_map and filename in self._c_files_map:
  369. c_file, rel_file_path, code = self._c_files_map[filename]
  370. else:
  371. c_file, _ = self._find_source_files(filename)
  372. if not c_file:
  373. + if standalone():
  374. + raise AssertionError(filename)
  375. return None # unknown file
  376. rel_file_path, code = self._read_source_lines(c_file, filename)
  377. if code is None:
  378. + if standalone():
  379. + raise AssertionError(filename)
  380. return None # no source found
  381. +
  382. return CythonModuleReporter(c_file, filename, rel_file_path, code)
  383. def _find_source_files(self, filename):
  384. @@ -132,6 +141,8 @@ class Plugin(CoveragePlugin):
  385. self._find_c_source_files(os.path.dirname(filename), filename)
  386. if filename in self._c_files_map:
  387. return self._c_files_map[filename][0], None
  388. + if standalone():
  389. + raise AssertionError(filename)
  390. else:
  391. # none of our business
  392. return None, None
  393. @@ -152,8 +163,8 @@ class Plugin(CoveragePlugin):
  394. py_source_file = None
  395. try:
  396. - with open(c_file, 'rb') as f:
  397. - if b'/* Generated by Cython ' not in f.read(30):
  398. + with OpenFile(c_file) as f:
  399. + if '/* Generated by Cython ' not in f.read(30):
  400. return None, None # not a Cython file
  401. except (IOError, OSError):
  402. c_file = None
  403. @@ -165,6 +176,20 @@ class Plugin(CoveragePlugin):
  404. Desperately parse all C files in the directory or its package parents
  405. (not re-descending) to find the (included) source file in one of them.
  406. """
  407. + if standalone():
  408. + if os.environ.get('PYTHON_COVERAGE_CYTHON_BUILD_ROOT'):
  409. + broot = os.environ['PYTHON_COVERAGE_CYTHON_BUILD_ROOT']
  410. + iter_files = lambda: (os.path.join(root, filename) for root, _, files in os.walk(broot) for filename in files)
  411. + else:
  412. + import library.python.resource
  413. + iter_files = library.python.resource.resfs_files
  414. + for c_file in iter_files():
  415. + if os.path.splitext(c_file)[1] in C_FILE_EXTENSIONS:
  416. + self._read_source_lines(c_file, source_file)
  417. + if source_file in self._c_files_map:
  418. + return
  419. + raise AssertionError((source_file, os.environ.get('PYTHON_COVERAGE_CYTHON_BUILD_ROOT')))
  420. +
  421. if not os.path.isdir(dir_path):
  422. return
  423. splitext = os.path.splitext
  424. @@ -223,7 +248,7 @@ class Plugin(CoveragePlugin):
  425. executable_lines = defaultdict(set)
  426. current_filename = None
  427. - with open(c_file) as lines:
  428. + with OpenFile(c_file) as lines:
  429. lines = iter(lines)
  430. for line in lines:
  431. match = match_source_path_line(line)
  432. @@ -280,7 +305,10 @@ class CythonModuleTracer(FileTracer):
  433. return self._file_path_map[source_file]
  434. except KeyError:
  435. pass
  436. - abs_path = _find_dep_file_path(filename, source_file)
  437. + if standalone():
  438. + abs_path = self.module_file
  439. + else:
  440. + abs_path = _find_dep_file_path(filename, source_file)
  441. if self.py_file and source_file[-3:].lower() == '.py':
  442. # always let coverage.py handle this case itself
  443. @@ -303,6 +331,7 @@ class CythonModuleReporter(FileReporter):
  444. self.name = rel_file_path
  445. self.c_file = c_file
  446. self._code = code
  447. + self._abs_filename = self._find_abs_filename()
  448. def lines(self):
  449. """
  450. @@ -323,8 +352,8 @@ class CythonModuleReporter(FileReporter):
  451. """
  452. Return the source code of the file as a string.
  453. """
  454. - if os.path.exists(self.filename):
  455. - with open_source_file(self.filename) as f:
  456. + if os.path.exists(self._abs_filename):
  457. + with open_source_file(self._abs_filename) as f:
  458. return f.read()
  459. else:
  460. return '\n'.join(
  461. @@ -335,14 +364,119 @@ class CythonModuleReporter(FileReporter):
  462. """
  463. Iterate over the source code tokens.
  464. """
  465. - if os.path.exists(self.filename):
  466. - with open_source_file(self.filename) as f:
  467. + if os.path.exists(self._abs_filename):
  468. + with open_source_file(self._abs_filename) as f:
  469. for line in f:
  470. yield [('txt', line.rstrip('\n'))]
  471. else:
  472. for line in self._iter_source_tokens():
  473. - yield [('txt', line)]
  474. + yield line
  475. +
  476. + def _find_abs_filename(self):
  477. + for root in [
  478. + os.environ.get('PYTHON_COVERAGE_ARCADIA_SOURCE_ROOT'),
  479. + os.environ.get('PYTHON_COVERAGE_CYTHON_BUILD_ROOT'),
  480. + ]:
  481. + if root:
  482. + abs_path = os.path.join(root, self.filename)
  483. + if root and os.path.exists(abs_path):
  484. + return abs_path
  485. + return self.filename
  486. def coverage_init(reg, options):
  487. reg.add_file_tracer(Plugin())
  488. +
  489. +
  490. +# ========================== Arcadia specific =================================
  491. +
  492. +def standalone():
  493. + return getattr(sys, 'is_standalone_binary', False)
  494. +
  495. +
  496. +class OpenFile(object):
  497. +
  498. + def __init__(self, filename, mode='r'):
  499. + assert 'r' in mode, ('Read-only', mode)
  500. + self.filename = filename
  501. + self.mode = mode
  502. + self.file = None
  503. + self.build_root = os.environ.get('PYTHON_COVERAGE_CYTHON_BUILD_ROOT')
  504. +
  505. + def __enter__(self):
  506. + # See redefined _find_c_source() description for more info
  507. + if self.build_root:
  508. + self.file = open(os.path.join(self.build_root, self.filename), self.mode)
  509. + return self.file
  510. + elif standalone():
  511. + import library.python.resource
  512. + from six import StringIO
  513. +
  514. + content = library.python.resource.resfs_read(self.filename, builtin=True)
  515. + assert content, (self.filename, os.environ.items())
  516. + return StringIO(content.decode())
  517. + else:
  518. + self.file = open(self.filename, self.mode)
  519. + return self.file
  520. +
  521. + def __exit__(self, exc_type, exc_val, exc_tb):
  522. + if self.file:
  523. + self.file.close()
  524. +
  525. +# ======================= Redefine some methods ===============================
  526. +
  527. +if standalone():
  528. + import itertools
  529. + import json
  530. +
  531. + CYTHON_INCLUDE_MAP = {'undef': True}
  532. +
  533. +
  534. + def _find_c_source(base_path):
  535. + '''
  536. + There are two different coverage stages when c source file might be required:
  537. + * trace - python calls c_tracefunc on every line and CythonModuleTracer needs to match
  538. + pyd and pxi files with source files. This is test's runtime and tests' clean environment might
  539. + doesn't contain required sources and generated files (c, cpp), that's why we get files from resfs_src.
  540. + * report - coverage data contains only covered data and CythonModuleReporter needs to
  541. + parse source files to obtain missing lines and branches. This is test_tool's resolve/build_report step.
  542. + test_tools doesn't have compiled in sources, however, it can extract required files
  543. + from binary and set PYTHON_COVERAGE_CYTHON_BUILD_ROOT to guide coverage.
  544. + '''
  545. + if os.environ.get('PYTHON_COVERAGE_CYTHON_BUILD_ROOT'):
  546. + # Report stage (resolve)
  547. + def exists(filename):
  548. + return os.path.exists(os.path.join(os.environ['PYTHON_COVERAGE_CYTHON_BUILD_ROOT'], filename))
  549. + else:
  550. + # Trace stage (test's runtime)
  551. + def exists(filename):
  552. + import library.python.resource
  553. + return library.python.resource.resfs_src(filename, resfs_file=True)
  554. +
  555. + if os.environ.get('PYTHON_COVERAGE_CYTHON_INCLUDE_MAP'):
  556. + if CYTHON_INCLUDE_MAP.get('undef'):
  557. + with open(os.environ['PYTHON_COVERAGE_CYTHON_INCLUDE_MAP']) as afile:
  558. + data = json.load(afile)
  559. + data = {os.path.splitext(k)[0]: v for k, v in data.items()}
  560. +
  561. + CYTHON_INCLUDE_MAP.clear()
  562. + CYTHON_INCLUDE_MAP.update(data)
  563. +
  564. + if base_path in CYTHON_INCLUDE_MAP:
  565. + # target file was included and should be sought inside another pyx file
  566. + base_path = CYTHON_INCLUDE_MAP[base_path]
  567. +
  568. + # TODO (', '.py3', '.py2') -> ('.py3', '.py2'), when https://a.yandex-team.ru/review/3511262 is merged
  569. + suffixes = [''.join(x) for x in itertools.product(('.pyx',), ('', '.py3', '.py2'), ('.cpp', '.c'))]
  570. + suffixes += C_FILE_EXTENSIONS
  571. +
  572. + for suffix in suffixes:
  573. + if exists(base_path + suffix):
  574. + return base_path + suffix
  575. +
  576. + return None
  577. +
  578. +
  579. + def _find_dep_file_path(main_file, file_path, relative_path_search=False):
  580. + # file_path is already arcadia root relative
  581. + return canonical_filename(file_path)
  582. --- contrib/tools/cython/Cython/Utility/CppConvert.pyx (index)
  583. +++ contrib/tools/cython/Cython/Utility/CppConvert.pyx (working tree)
  584. @@ -235,3 +235,150 @@ cdef object {{cname}}(const std_complex[X]& z):
  585. tmp.real = <double>z.real()
  586. tmp.imag = <double>z.imag()
  587. return tmp
  588. +
  589. +
  590. +#################### arcadia_TMaybe.from_py ####################
  591. +
  592. +cdef extern from *:
  593. + cdef cppclass TMaybe [T]:
  594. + TMaybe()
  595. + TMaybe(T&)
  596. + TMaybe& operator =(T&)
  597. +
  598. +@cname("{{cname}}")
  599. +cdef TMaybe[X] {{cname}}(object o) except *:
  600. + cdef TMaybe[X] result
  601. + if o is not None:
  602. + result = <X>o
  603. + return result
  604. +
  605. +#################### arcadia_TMaybe.to_py ####################
  606. +
  607. +cdef extern from *:
  608. + cdef cppclass TMaybe [T]:
  609. + bint Defined()
  610. + T& GetRef()
  611. +
  612. +@cname("{{cname}}")
  613. +cdef object {{cname}}(const TMaybe[X]& s):
  614. + if s.Defined():
  615. + return s.GetRef()
  616. + return None
  617. +
  618. +
  619. +#################### arcadia_TVector.from_py ####################
  620. +
  621. +cdef extern from *:
  622. + cdef cppclass TVector [T]:
  623. + void push_back(T&)
  624. +
  625. +@cname("{{cname}}")
  626. +cdef TVector[X] {{cname}}(object o) except *:
  627. + cdef TVector[X] v
  628. + for item in o:
  629. + v.push_back(<X>item)
  630. + return v
  631. +
  632. +
  633. +#################### arcadia_TVector.to_py ####################
  634. +
  635. +cdef extern from *:
  636. + cdef cppclass TVector [T]:
  637. + size_t size()
  638. + T& operator[](size_t)
  639. +
  640. +@cname("{{cname}}")
  641. +cdef object {{cname}}(const TVector[X]& v):
  642. + return [v[i] for i in range(v.size())]
  643. +
  644. +
  645. +#################### arcadia_THashMap.from_py ####################
  646. +
  647. +cdef extern from *:
  648. + cdef cppclass pair "std::pair" [T, U]:
  649. + pair(T&, U&)
  650. + cdef cppclass THashMap [T, U]:
  651. + void insert(pair[T, U]&)
  652. +
  653. +
  654. +@cname("{{cname}}")
  655. +cdef THashMap[X,Y] {{cname}}(object o) except *:
  656. + cdef dict d = o
  657. + cdef THashMap[X,Y] m
  658. + for key, value in d.iteritems():
  659. + m.insert(pair[X,Y](<X>key, <Y>value))
  660. + return m
  661. +
  662. +
  663. +#################### arcadia_THashMap.to_py ####################
  664. +
  665. +cimport cython
  666. +
  667. +cdef extern from *:
  668. + cdef cppclass THashMap [T, U]:
  669. + cppclass value_type:
  670. + T first
  671. + U second
  672. + cppclass const_iterator:
  673. + value_type& operator*()
  674. + const_iterator operator++()
  675. + bint operator!=(const_iterator)
  676. + const_iterator begin()
  677. + const_iterator end()
  678. +
  679. +@cname("{{cname}}")
  680. +cdef dict {{cname}}(const THashMap[X,Y]& s):
  681. + cdef dict result = {}
  682. + cdef const THashMap[X,Y].value_type *key_value
  683. + cdef THashMap[X,Y].const_iterator iter = s.begin()
  684. + while iter != s.end():
  685. + key_value = &cython.operator.dereference(iter)
  686. + result[key_value.first] = key_value.second
  687. + cython.operator.preincrement(iter)
  688. + return result
  689. +
  690. +
  691. +#################### arcadia_TMap.from_py ####################
  692. +
  693. +cdef extern from *:
  694. + cdef cppclass pair "std::pair" [T, U]:
  695. + pair(T&, U&)
  696. + cdef cppclass TMap [T, U]:
  697. + void insert(pair[T, U]&)
  698. +
  699. +
  700. +@cname("{{cname}}")
  701. +cdef TMap[X,Y] {{cname}}(object o) except *:
  702. + cdef dict d = o
  703. + cdef TMap[X,Y] m
  704. + for key, value in d.iteritems():
  705. + m.insert(pair[X,Y](<X>key, <Y>value))
  706. + return m
  707. +
  708. +
  709. +#################### arcadia_TMap.to_py ####################
  710. +
  711. +cimport cython
  712. +
  713. +cdef extern from *:
  714. + cdef cppclass TMap [T, U]:
  715. + cppclass value_type:
  716. + T first
  717. + U second
  718. + cppclass const_iterator:
  719. + value_type& operator*()
  720. + const_iterator operator++()
  721. + bint operator!=(const_iterator)
  722. + const_iterator begin()
  723. + const_iterator end()
  724. +
  725. +@cname("{{cname}}")
  726. +cdef dict {{cname}}(const TMap[X,Y]& s):
  727. + cdef dict result = {}
  728. + cdef const TMap[X,Y].value_type *key_value
  729. + cdef TMap[X,Y].const_iterator iter = s.begin()
  730. + while iter != s.end():
  731. + key_value = &cython.operator.dereference(iter)
  732. + result[key_value.first] = key_value.second
  733. + cython.operator.preincrement(iter)
  734. + return result
  735. --- contrib/tools/cython/Cython/Utility/Embed.c (index)
  736. +++ contrib/tools/cython/Cython/Utility/Embed.c (working tree)
  737. @@ -5,6 +5,8 @@
  738. #endif
  739. #if PY_MAJOR_VERSION < 3
  740. +void Py_InitArgcArgv(int argc, char **argv);
  741. +
  742. int %(main_method)s(int argc, char** argv) {
  743. #elif defined(WIN32) || defined(MS_WINDOWS)
  744. int %(wmain_method)s(int argc, wchar_t **argv) {
  745. @@ -22,8 +28,10 @@ static int __Pyx_main(int argc, wchar_t **argv) {
  746. m = fpgetmask();
  747. fpsetmask(m & ~FP_X_OFL);
  748. #endif
  749. - if (argc && argv)
  750. + if (argc && argv) {
  751. + Py_InitArgcArgv(argc, argv);
  752. Py_SetProgramName(argv[0]);
  753. + }
  754. Py_Initialize();
  755. if (argc && argv)
  756. PySys_SetArgv(argc, argv);
  757. --- contrib/tools/cython/Cython/Utility/ModuleSetupCode.c (index)
  758. +++ contrib/tools/cython/Cython/Utility/ModuleSetupCode.c (working tree)
  759. @@ -1,5 +1,15 @@
  760. /////////////// CModulePreamble ///////////////
  761. +#if defined(__GNUC__) || defined(__clang__)
  762. +#pragma GCC diagnostic push
  763. +#pragma GCC diagnostic ignored "-Wshadow"
  764. +#pragma GCC diagnostic ignored "-Wunused-function"
  765. +#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
  766. +// Ignore tp_print initializer. Need for ya make -DUSE_SYSTEM_PYTHON=3.8
  767. +#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  768. +#endif
  769. +#endif
  770. +
  771. #include <stddef.h> /* For offsetof */
  772. #ifndef offsetof
  773. #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
  774. --- contrib/tools/cython/Cython/Utility/Optimize.c (index)
  775. +++ contrib/tools/cython/Cython/Utility/Optimize.c (working tree)
  776. @@ -886,7 +886,7 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED
  777. }
  778. return PyInt_FromLong(x);
  779. {{elif op == 'Lshift'}}
  780. - if (likely(b < (long) (sizeof(long)*8) && a == (a << b) >> b) || !a) {
  781. + if (likely(b < (int)(sizeof(long)*8) && a == (a << b) >> b) || !a) {
  782. return PyInt_FromLong(a {{c_op}} b);
  783. }
  784. {{else}}
  785. @@ -980,12 +980,12 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED
  786. x = a {{c_op}} b;
  787. {{if op == 'Lshift'}}
  788. #ifdef HAVE_LONG_LONG
  789. - if (unlikely(!(b < (long) (sizeof(long)*8) && a == x >> b)) && a) {
  790. + if (unlikely(!(b < (int)(sizeof(long)*8) && a == x >> b)) && a) {
  791. ll{{ival}} = {{ival}};
  792. goto long_long;
  793. }
  794. #else
  795. - if (likely(b < (long) (sizeof(long)*8) && a == x >> b) || !a) /* execute return statement below */
  796. + if (likely(b < (int)(sizeof(long)*8) && a == x >> b) || !a) /* execute return statement below */
  797. #endif
  798. {{endif}}
  799. {{endif}}
  800. @@ -1039,9 +1039,9 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, CYTHON_UNUSED
  801. }
  802. {{endif}}
  803. // copied from floatobject.c in Py3.5:
  804. - PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL)
  805. +// PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL)
  806. result = ((double)a) {{c_op}} (double)b;
  807. - PyFPE_END_PROTECT(result)
  808. +// PyFPE_END_PROTECT(result)
  809. return PyFloat_FromDouble(result);
  810. {{endif}}
  811. }
  812. @@ -1178,7 +1178,7 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, double floatv
  813. {{else}}
  814. // copied from floatobject.c in Py3.5:
  815. {{if order == 'CObj' and c_op in '%/'}}{{zerodiv_check('b')}}{{endif}}
  816. - PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL)
  817. +// PyFPE_START_PROTECT("{{op.lower() if not op.endswith('Divide') else 'divide'}}", return NULL)
  818. {{if c_op == '%'}}
  819. result = fmod(a, b);
  820. if (result)
  821. @@ -1188,7 +1188,7 @@ static {{c_ret_type}} {{cfunc_name}}(PyObject *op1, PyObject *op2, double floatv
  822. {{else}}
  823. result = a {{c_op}} b;
  824. {{endif}}
  825. - PyFPE_END_PROTECT(result)
  826. +// PyFPE_END_PROTECT(result)
  827. return PyFloat_FromDouble(result);
  828. {{endif}}
  829. }
  830. --- contrib/tools/cython/Cython/Utility/StringTools.c (index)
  831. +++ contrib/tools/cython/Cython/Utility/StringTools.c (working tree)
  832. @@ -454,7 +454,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16BE(const char *s, Py_s
  833. //@requires: decode_c_bytes
  834. static CYTHON_INLINE PyObject* __Pyx_decode_cpp_string(
  835. - std::string cppstring, Py_ssize_t start, Py_ssize_t stop,
  836. + std::string_view cppstring, Py_ssize_t start, Py_ssize_t stop,
  837. const char* encoding, const char* errors,
  838. PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors)) {
  839. return __Pyx_decode_c_bytes(
  840. --- contrib/tools/cython/cython.py (index)
  841. +++ contrib/tools/cython/cython.py (working tree)
  842. @@ -1,5 +1,7 @@
  843. #!/usr/bin/env python
  844. +# Change content of this file to change uids for cython programs - cython
  845. +
  846. #
  847. # Cython -- Main Program, generic
  848. #
  849. @@ -8,6 +10,7 @@ if __name__ == '__main__':
  850. import os
  851. import sys
  852. + sys.dont_write_bytecode = True
  853. # Make sure we import the right Cython
  854. cythonpath, _ = os.path.split(os.path.realpath(__file__))