Skip to content

Commit

Permalink
sage.doctest: multiprocessing import fixes for pyodide
Browse files Browse the repository at this point in the history
  • Loading branch information
mkoeppe committed Jan 28, 2024
1 parent 5a60f0c commit 343f575
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 10 deletions.
10 changes: 7 additions & 3 deletions src/sage/doctest/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@
# http://www.gnu.org/licenses/
#*****************************************************************************

import multiprocessing
import os


# With OS X, Python 3.8 defaults to use 'spawn' instead of 'fork' in
# multiprocessing, and Sage doctesting doesn't work with 'spawn'. See
# trac #27754.
if os.uname().sysname == 'Darwin':
import multiprocessing
multiprocessing.set_start_method('fork', force=True)
Array = multiprocessing.Array

# Functions in this module whose name is of the form 'has_xxx' tests if the
# software xxx is available to Sage.
Expand Down Expand Up @@ -428,7 +428,11 @@ def __init__(self):
features.update(all_features())
self._features = sorted(features, key=lambda feature: feature.name)
self._indices = {feature.name: idx for idx, feature in enumerate(self._features)}
self._seen = Array('i', len(self._features)) # initialized to zeroes
try:
from multiprocessing import Array
self._seen = Array('i', len(self._features)) # initialized to zeroes
except ImportError: # module '_multiprocessing' is removed in Pyodide due to browser limitations
self._seen = [0] * len(self._features)

def __contains__(self, item):
"""
Expand Down
20 changes: 14 additions & 6 deletions src/sage/doctest/forker.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import signal
import linecache
import hashlib
import multiprocessing
import warnings
import re
import errno
Expand Down Expand Up @@ -80,8 +79,17 @@
# multiprocessing, and Sage doctesting doesn't work with 'spawn'. See
# trac #27754.
if os.uname().sysname == 'Darwin':
import multiprocessing
multiprocessing.set_start_method('fork', force=True)

try:
import multiprocessing
from multiprocessing import Process
except ImportError:
multiprocessing = None
class Process:
pass


def _sorted_dict_pprinter_factory(start, end):
"""
Expand Down Expand Up @@ -1457,7 +1465,7 @@ def report_failure(self, out, test, example, got, globs):
except KeyboardInterrupt:
# Assume this is a *real* interrupt. We need to
# escalate this to the master doctesting process.
if not self.options.serial:
if not self.options.serial and multiprocessing:
os.kill(os.getppid(), signal.SIGINT)
raise
finally:
Expand Down Expand Up @@ -1594,7 +1602,7 @@ def report_unexpected_exception(self, out, test, example, exc_info):
except KeyboardInterrupt:
# Assume this is a *real* interrupt. We need to
# escalate this to the master doctesting process.
if not self.options.serial:
if not self.options.serial and multiprocessing:
os.kill(os.getppid(), signal.SIGINT)
raise
finally:
Expand Down Expand Up @@ -2106,13 +2114,13 @@ def dispatch(self):
sage -t .../sage/rings/big_oh.py
[... tests, ... s]
"""
if self.controller.options.serial:
if self.controller.options.serial or not multiprocessing:
self.serial_dispatch()
else:
self.parallel_dispatch()


class DocTestWorker(multiprocessing.Process):
class DocTestWorker(Process):
"""
The DocTestWorker process runs one :class:`DocTestTask` for a given
source. It returns messages about doctest failures (or all tests if
Expand Down Expand Up @@ -2176,7 +2184,7 @@ def __init__(self, source, options, funclist=[], baseline=None):
cumulative wall time: ... seconds
Features detected...
"""
multiprocessing.Process.__init__(self)
Process.__init__(self)

self.source = source
self.options = options
Expand Down
3 changes: 2 additions & 1 deletion src/sage/parallel/multiprocessing_sage.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
# https://www.gnu.org/licenses/
################################################################################

from multiprocessing import Pool
from functools import partial
from sage.misc.fpickle import pickle_function, call_pickled_function
from . import ncpus
Expand Down Expand Up @@ -67,6 +66,8 @@ def parallel_iter(processes, f, inputs):
sage: v.sort(); v
[(((2,), {}), 4), (((3,), {}), 6)]
"""
from multiprocessing import Pool

if processes == 0:
processes = ncpus.ncpus()
p = Pool(processes)
Expand Down

0 comments on commit 343f575

Please sign in to comment.