Skip to content

Commit

Permalink
Merge pull request #150 from bluescarni/pr/py312_fixes
Browse files Browse the repository at this point in the history
Fixes for Python 3.12
  • Loading branch information
bluescarni authored Feb 20, 2024
2 parents 44c5d1a + 76d0e4a commit af61e8c
Show file tree
Hide file tree
Showing 27 changed files with 2,287 additions and 1,453 deletions.
2 changes: 0 additions & 2 deletions doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ pygmo has the following **mandatory** runtime dependencies:
Additionally, pygmo has the following **optional** runtime
dependencies:

* `dill <https://dill.readthedocs.io>`__, which can be used as an
alternative serialization backend,
* `Matplotlib <https://matplotlib.org/>`__, which is used by a few
plotting utilities,
* `NetworkX <https://networkx.github.io/>`__, which is used for
Expand Down
138 changes: 87 additions & 51 deletions pygmo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,38 @@
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

from ._check_deps import *

# Version setup.
from ._version import __version__

# We import the sub-modules into the root namespace
from .core import *
from .plotting import *
from ._py_islands import *
from ._py_problems import *
from ._py_bfes import *
from ._py_algorithms import *

# Patch the problem class.
from . import _patch_problem

# Patch the algorithm class.
from . import _patch_algorithm

# Patch the bfe class.
from . import _patch_bfe

# Patch the island class.
from . import _patch_island

# Patch the policies.
from . import _patch_r_policy
from . import _patch_s_policy

# Patch the topology.
from . import _patch_topology
import cloudpickle as _cloudpickle

# Explicitly import the test submodule
from . import test
import atexit as _atexit
Expand Down Expand Up @@ -69,7 +78,7 @@
# of the syntax translate(udp, translation) for all udps


def _translate_init(self, prob=None, translation=[0.]):
def _translate_init(self, prob=None, translation=[0.0]):
"""
Args:
prob: a user-defined problem (either Python or C++), or an instance of :class:`~pygmo.problem`
Expand Down Expand Up @@ -109,13 +118,20 @@ def _translate_init(self, prob=None, translation=[0.]):
# of the syntax decompose(udp, ..., ) for all udps


def _decompose_init(self, prob=None, weight=[0.5, 0.5], z=[0., 0.], method='weighted', adapt_ideal=False):
def _decompose_init(
self,
prob=None,
weight=[0.5, 0.5],
z=[0.0, 0.0],
method="weighted",
adapt_ideal=False,
):
"""
Args:
prob: a user-defined problem (either Python or C++), or an instance of :class:`~pygmo.problem`
(if *prob* is :data:`None`, a :class:`~pygmo.null_problem` will be used in its stead)
weight (array-like object): the vector of weights :math:`\\boldsymbol \lambda`
z (array-like object): the reference point :math:`\mathbf z^*`
weight (array-like object): the vector of weights :math:`\\boldsymbol \\lambda`
z (array-like object): the reference point :math:`\\mathbf z^*`
method (str): a string containing the decomposition method chosen
adapt_ideal (bool): when :data:`True`, the reference point is adapted at each fitness evaluation
to be the ideal point
Expand Down Expand Up @@ -273,6 +289,7 @@ def _population_init(self, prob=None, size=0, b=None, seed=None):
"""
from .core import _random_device_next

# Check input params.
if not isinstance(size, int):
raise TypeError("the 'size' parameter must be an integer")
Expand All @@ -296,8 +313,9 @@ def _population_init(self, prob=None, size=0, b=None, seed=None):
__original_population_init(self, prob, size, seed)
else:
# A bfe was specified. Same as above with the problem.
__original_population_init(self, prob, b if type(
b) == bfe else bfe(b), size, seed)
__original_population_init(
self, prob, b if type(b) == bfe else bfe(b), size, seed
)


setattr(population, "__init__", _population_init)
Expand Down Expand Up @@ -334,56 +352,63 @@ def _island_init(self, **kwargs):
return

# If we are not dealing with a def ctor, we always need the algo argument.
if not 'algo' in kwargs:
if not "algo" in kwargs:
raise KeyError(
"the mandatory 'algo' parameter is missing from the list of arguments "
"of the island constructor")
algo = kwargs.pop('algo')
"of the island constructor"
)
algo = kwargs.pop("algo")
algo = algo if type(algo) == algorithm else algorithm(algo)

# Population setup. We either need an input pop, or the prob and size,
# plus optionally seed and b.
if 'pop' in kwargs and ('prob' in kwargs or 'size' in kwargs or 'seed' in kwargs or 'b' in kwargs):
if "pop" in kwargs and (
"prob" in kwargs or "size" in kwargs or "seed" in kwargs or "b" in kwargs
):
raise KeyError(
"if the 'pop' argument is provided, the 'prob', 'size', 'seed' and 'b' "
"arguments must not be provided")
elif 'pop' in kwargs:
pop = kwargs.pop('pop')
elif 'prob' in kwargs and 'size' in kwargs:
pop = population(prob=kwargs.pop('prob'),
size=kwargs.pop('size'), seed=kwargs.pop('seed') if 'seed' in kwargs else None,
b=kwargs.pop('b') if 'b' in kwargs else None)
"arguments must not be provided"
)
elif "pop" in kwargs:
pop = kwargs.pop("pop")
elif "prob" in kwargs and "size" in kwargs:
pop = population(
prob=kwargs.pop("prob"),
size=kwargs.pop("size"),
seed=kwargs.pop("seed") if "seed" in kwargs else None,
b=kwargs.pop("b") if "b" in kwargs else None,
)
else:
raise KeyError(
"unable to construct a population from the arguments of "
"the island constructor: you must either pass a population "
"('pop') or a set of arguments that can be used to build one "
"('prob', 'size' and, optionally, 'seed' and 'b')")
"('prob', 'size' and, optionally, 'seed' and 'b')"
)

# UDI, if any.
if 'udi' in kwargs:
args = [kwargs.pop('udi'), algo, pop]
if "udi" in kwargs:
args = [kwargs.pop("udi"), algo, pop]
else:
args = [algo, pop]

# Replace/selection policies, if any.
if 'r_pol' in kwargs:
r_pol = kwargs.pop('r_pol')
if "r_pol" in kwargs:
r_pol = kwargs.pop("r_pol")
r_pol = r_pol if type(r_pol) == r_policy else r_policy(r_pol)
args.append(r_pol)
else:
args.append(r_policy())

if 's_pol' in kwargs:
s_pol = kwargs.pop('s_pol')
if "s_pol" in kwargs:
s_pol = kwargs.pop("s_pol")
s_pol = s_pol if type(s_pol) == s_policy else s_policy(s_pol)
args.append(s_pol)
else:
args.append(s_policy())

if len(kwargs) != 0:
raise KeyError(
'unrecognised keyword arguments: {}'.format(list(kwargs.keys())))
raise KeyError("unrecognised keyword arguments: {}".format(list(kwargs.keys())))

__original_island_init(self, *args)

Expand Down Expand Up @@ -417,6 +442,7 @@ def _mbh_init(self, algo=None, stop=5, perturb=1e-2, seed=None):
"""
import numbers

if algo is None:
# Use the compass search algo for default init.
algo = compass_search()
Expand Down Expand Up @@ -538,40 +564,43 @@ def _archi_init(self, n=0, t=topology(), **kwargs):
raise TypeError("the 'n' parameter must be an integer")
if n < 0:
raise ValueError(
"the 'n' parameter must be non-negative, but it is {} instead".format(n))
"the 'n' parameter must be non-negative, but it is {} instead".format(n)
)

# Replace the 'pop_size' kw arg with just 'size', for later use in the
# island ctor.

if 'size' in kwargs:
if "size" in kwargs:
raise KeyError(
"the 'size' argument cannot appear among the named arguments of the archipelago constructor")
"the 'size' argument cannot appear among the named arguments of the archipelago constructor"
)

if 'pop_size' in kwargs:
if "pop_size" in kwargs:
# Extract 'pop_size', replace with just 'size'.
ps_val = kwargs.pop('pop_size')
kwargs['size'] = ps_val
ps_val = kwargs.pop("pop_size")
kwargs["size"] = ps_val

# Call the original init, which constructs an empty archi from a topology.
t = t if type(t) == topology else topology(t)
__original_archi_init(self, t)

if 'seed' in kwargs:
if "seed" in kwargs:
# Special handling of the 'seed' argument.
from random import Random
from .core import _max_unsigned

# Create a random engine with own state.
RND = Random()
# Get the seed from kwargs.
seed = kwargs.pop('seed')
seed = kwargs.pop("seed")
if not isinstance(seed, int):
raise TypeError("the 'seed' parameter must be an integer")
# Seed the rng.
RND.seed(seed)
u_max = _max_unsigned()
# Push back the islands with different seed.
for _ in range(n):
kwargs['seed'] = RND.randint(0, u_max)
kwargs["seed"] = RND.randint(0, u_max)
self.push_back(**kwargs)

else:
Expand Down Expand Up @@ -621,13 +650,22 @@ def _archi_push_back(self, *args, **kwargs):
else:
if len(args) != 1:
raise ValueError(
"{} positional arguments were provided, but this method accepts only a single positional argument".format(len(args)))
"{} positional arguments were provided, but this method accepts only a single positional argument".format(
len(args)
)
)
if len(kwargs) != 0:
raise ValueError(
"if a positional argument is passed to this method, then no keyword arguments must be passed, but {} keyword arguments were passed instead".format(len(kwargs)))
"if a positional argument is passed to this method, then no keyword arguments must be passed, but {} keyword arguments were passed instead".format(
len(kwargs)
)
)
if type(args[0]) != island:
raise TypeError(
"the positional argument passed to this method must be an island, but the type of the argument is '{}' instead".format(type(args[0])))
"the positional argument passed to this method must be an island, but the type of the argument is '{}' instead".format(
type(args[0])
)
)
self._push_back(args[0])


Expand Down Expand Up @@ -708,8 +746,7 @@ def set_serialization_backend(name):
The valid backends are:
* ``'pickle'`` (i.e., the standard Python :mod:`pickle` module),
* ``'cloudpickle'``,
* ``'dill'`` (from the `dill <https://pypi.org/project/dill/>`__ library).
* ``'cloudpickle'``.
.. warning::
Expand All @@ -722,29 +759,28 @@ def set_serialization_backend(name):
Raises:
TypeError: if *name* is not a :class:`str`
ValueError: if *name* is not one of ``['pickle', 'cloudpickle', 'dill']``
ImportError: if *name* is ``'dill'`` but the dill module is not installed
ValueError: if *name* is not one of ``['pickle', 'cloudpickle']``
"""
if not isinstance(name, str):
raise TypeError(
"The serialization backend must be specified as a string, but an object of type {} was provided instead".format(type(name)))
"The serialization backend must be specified as a string, but an object of type {} was provided instead".format(
type(name)
)
)
global _serialization_backend
if name == "pickle":
import pickle

_serialization_backend = pickle
elif name == "cloudpickle":
_serialization_backend = _cloudpickle
elif name == "dill":
try:
import dill
_serialization_backend = dill
except ImportError:
raise ImportError(
"The 'dill' serialization backend was specified, but the dill module is not installed.")
else:
raise ValueError(
"The serialization backend '{}' is not valid. The valid backends are: ['pickle', 'cloudpickle', 'dill']".format(name))
"The serialization backend '{}' is not valid. The valid backends are: ['pickle', 'cloudpickle']".format(
name
)
)


def get_serialization_backend():
Expand Down
Loading

0 comments on commit af61e8c

Please sign in to comment.