diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a1a724f59..b47f73443 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,6 +15,10 @@ jobs: strategy: matrix: include: + - python-version: "3.14.0-alpha.1" + with-opt-deps: true + runs-on: ubuntu-22.04 + - python-version: "3.13.0" with-opt-deps: true runs-on: ubuntu-22.04 diff --git a/src/callbacks.py b/src/callbacks.py index e3772c81b..69eea38c0 100644 --- a/src/callbacks.py +++ b/src/callbacks.py @@ -1355,12 +1355,8 @@ class CommandProcess(world.SupyProcess): pn, cn) log.debug('Spawning process %s (args: %r)', procName, args) - self.__parent = super(CommandProcess, self) - self.__parent.__init__(target=target, name=procName, - args=args, kwargs=kwargs) - - def run(self): - self.__parent.run() + super().__init__(target=target, name=procName, + args=args, kwargs=kwargs) class CanonicalString(registry.NormalizedString): def normalize(self, s): diff --git a/src/commands.py b/src/commands.py index 7c11ff5d2..c57e75fe2 100644 --- a/src/commands.py +++ b/src/commands.py @@ -88,6 +88,20 @@ def _rlimit_min(a, b): else: return min(soft, heap_size) +def _process_target(f, q, heap_size, *args, **kwargs): + """Called by :func:`process`""" + if resource: + rsrc = resource.RLIMIT_DATA + (soft, hard) = resource.getrlimit(rsrc) + soft = _rlimit_min(soft, heap_size) + hard = _rlimit_min(hard, heap_size) + resource.setrlimit(rsrc, (soft, hard)) + try: + r = f(*args, **kwargs) + q.put([False, r]) + except Exception as e: + q.put([True, e]) + def process(f, *args, **kwargs): """Runs a function in a subprocess. @@ -122,21 +136,9 @@ def process(f, *args, **kwargs): '(See https://github.com/travis-ci/travis-core/issues/187\n' 'for more information about this bug.)\n') raise - def newf(f, q, *args, **kwargs): - if resource: - rsrc = resource.RLIMIT_DATA - (soft, hard) = resource.getrlimit(rsrc) - soft = _rlimit_min(soft, heap_size) - hard = _rlimit_min(hard, heap_size) - resource.setrlimit(rsrc, (soft, hard)) - try: - r = f(*args, **kwargs) - q.put([False, r]) - except Exception as e: - q.put([True, e]) - targetArgs = (f, q,) + args - p = callbacks.CommandProcess(target=newf, - args=targetArgs, kwargs=kwargs) + targetArgs = (f, q, heap_size) + args + p = callbacks.CommandProcess(target=_process_target, + args=targetArgs, kwargs=kwargs) try: p.start() except OSError as e: diff --git a/src/utils/math_evaluator.py b/src/utils/math_evaluator.py index b7ef34027..ff04009ab 100644 --- a/src/utils/math_evaluator.py +++ b/src/utils/math_evaluator.py @@ -154,8 +154,16 @@ class SafeEvalVisitor(ast.NodeVisitor): return self.visit(node.body) def visit_Num(self, node): + """Python < 3.14 only""" return self._convert_num(node.n) + def visit_Constant(self, node): + """Python >= 3.14 only""" + if type(node.value) in (float, complex, int): + return self._convert_num(node.value) + else: + raise InvalidNode('illegal constant %s' % node.value) + def visit_Name(self, node): id_ = node.id.lower() if id_ in self._env: diff --git a/src/utils/str.py b/src/utils/str.py index c9a86c21e..5fe7ae943 100644 --- a/src/utils/str.py +++ b/src/utils/str.py @@ -307,9 +307,9 @@ def perlReToReplacer(s): flags = ''.join(flags) r = perlReToPythonRe(sep.join(('', regexp, flags))) if g: - return lambda s: r.sub(replace, s) + return functools.partial(r.sub, replace) else: - return lambda s: r.sub(replace, s, 1) + return functools.partial(r.sub, replace, count=1) _perlVarSubstituteRe = re.compile(r'\$\{([^}]+)\}|\$([a-zA-Z][a-zA-Z0-9]*)') def perlVariableSubstitute(vars, text): diff --git a/src/world.py b/src/world.py index 85f581ec5..75f994682 100644 --- a/src/world.py +++ b/src/world.py @@ -65,7 +65,7 @@ class SupyThread(threading.Thread, object): log.debug('Spawning thread %q.', self.getName()) processesSpawned = 1 # Starts at one for the initial process. -class SupyProcess(multiprocessing.Process): +class SupyProcess(multiprocessing.get_context('fork').Process): def __init__(self, *args, **kwargs): global processesSpawned processesSpawned += 1