Skip to content

Commit

Permalink
Merge for version 3.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
SGenheden committed Apr 28, 2022
2 parents 015fbcc + 20ffc06 commit ceaa9d8
Show file tree
Hide file tree
Showing 29 changed files with 1,017 additions and 865 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# CHANGELOG

## Version 3.4.0 2022-04-28

### Features

- Gracefully fail predictions with aizynthcli if target is unsanitizable (Github issue 66)

### Trivial changes
- Update version of Sphinx, scikit-learn and Black
- Remove usage of depracted Pandas function append (Github issue 63)
- Correct documentation of aizynthcli (Github issue 67)

## Version 3.3.1 2022-03-09

### Trivial changes
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Before you begin, ensure you have met the following requirements:

* Linux, Windows or macOS platforms are supported - as long as the dependencies are supported on these platforms.

* You have installed [anaconda](https://www.anaconda.com/) or [miniconda](https://docs.conda.io/en/latest/miniconda.html) with python 3.6 - 3.8
* You have installed [anaconda](https://www.anaconda.com/) or [miniconda](https://docs.conda.io/en/latest/miniconda.html) with python 3.6 - 3.9

The tool has been developed on a Linux platform, but the software has been tested on Windows 10 and macOS Catalina.

Expand Down Expand Up @@ -62,7 +62,7 @@ First, install these conda packages

Secondly, install the ``aizynthfinder`` package

python -m pip install https://github.com/MolecularAI/aizynthfinder/archive/v3.3.1.tar.gz
python -m pip install https://github.com/MolecularAI/aizynthfinder/archive/v3.4.0.tar.gz


if you want to install the latest version
Expand Down
6 changes: 6 additions & 0 deletions aizynthfinder/aizynthfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
)
from aizynthfinder.chem import Molecule, TreeMolecule, FixedRetroReaction
from aizynthfinder.search.andor_trees import AndOrSearchTreeBase
from aizynthfinder.utils.exceptions import MoleculeException

if TYPE_CHECKING:
from aizynthfinder.utils.type_utils import (
Expand Down Expand Up @@ -148,6 +149,11 @@ def prepare_tree(self) -> None:
if not self.target_mol:
raise ValueError("No target molecule set")

try:
self.target_mol.sanitize()
except MoleculeException:
raise ValueError("Target molecule unsanitizable")

self.stock.reset_exclusion_list()
if self.config.exclude_target_from_stock and self.target_mol in self.stock:
self.stock.exclude(self.target_mol)
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/analysis/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def cluster(
n_clusters: int,
max_clusters: int = 5,
distances_model: str = "ted",
**kwargs: Any
**kwargs: Any,
) -> np.ndarray:
"""
Cluster the route collection into a number of clusters.
Expand Down
1 change: 1 addition & 0 deletions aizynthfinder/analysis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class RouteSelectionArguments:
If `return_all` is True, it will return all solved routes if there is at least one is solved, otherwise
the `nmin` and `nmax` will be used.
"""

nmin: int = 5
nmax: int = 25
return_all: bool = False
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/chem/mol.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def inchi_key(self) -> str:

@property
def weight(self) -> float:
""" Return the exact molecular weight of the molecule """
"""Return the exact molecular weight of the molecule"""
self.sanitize(raise_exception=False)
return Descriptors.ExactMolWt(self.rd_mol)

Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/chem/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def __str__(self) -> str:

@property
def rd_reaction(self) -> RdReaction:
""" Return the RDKit reaction created from the SMART """
"""Return the RDKit reaction created from the SMART"""
if self._rd_reaction is None:
self._rd_reaction = AllChem.ReactionFromSmarts(self.smarts)
return self._rd_reaction
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/context/cost/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


class MoleculeCost(ContextCollection):
""" Collection of molecular cost objects """
"""Collection of molecular cost objects"""

_single_selection: bool = True
_collection_name: str = "molecule cost"
Expand Down
12 changes: 10 additions & 2 deletions aizynthfinder/interfaces/aizynthcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,11 @@ def _process_single_smiles(
) -> None:
output_name = output_name or "trees.json"
finder.target_smiles = smiles
finder.prepare_tree()
try:
finder.prepare_tree()
except ValueError as err:
print(f"Failed to setup search due to: '{str(err).lower()}'")
return
finder.tree_search(show_progress=True)
finder.build_routes()

Expand Down Expand Up @@ -179,7 +183,11 @@ def _process_multi_smiles(
results = defaultdict(list)
for smi in smiles:
finder.target_smiles = smi
finder.prepare_tree()
try:
finder.prepare_tree()
except ValueError as err:
print(f"Failed to setup search for {smi} due to: '{str(err).lower()}'")
continue
search_time = finder.tree_search()
finder.build_routes()
stats = finder.extract_statistics()
Expand Down
16 changes: 8 additions & 8 deletions aizynthfinder/search/andor_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,39 @@


class TreeNodeMixin:
""" A mixin class for node in a tree """
"""A mixin class for node in a tree"""

@property
def prop(self) -> StrDict:
""" Dictionary with publicly exposed properties """
"""Dictionary with publicly exposed properties"""
return {}

@property
def children(self) -> List["TreeNodeMixin"]:
""" List of children nodes """
"""List of children nodes"""
return []


class AndOrSearchTreeBase(abc.ABC):
""" A base class for a search tree based on an AND/OR structure """
"""A base class for a search tree based on an AND/OR structure"""

def __init__(self, config: Configuration, root_smiles: str = None) -> None:
self.config = config
self._root_smiles = root_smiles

@property
def mol_nodes(self) -> List[TreeNodeMixin]:
""" Return the molecule nodes of the tree """
"""Return the molecule nodes of the tree"""
return []

@abc.abstractmethod
def one_iteration(self) -> bool: # pylint: disable=no-self-use
""" Perform one iteration of the search """
"""Perform one iteration of the search"""
return False

@abc.abstractmethod
def routes(self) -> List[ReactionTree]: # pylint: disable=no-self-use
""" Return the routes of the tree """
"""Return the routes of the tree"""
return []


Expand Down Expand Up @@ -150,7 +150,7 @@ def __init__(self, root: TreeNodeMixin = None) -> None:

@property
def first_reaction(self) -> TreeNodeMixin:
""" Return the first reaction or raise an exception """
"""Return the first reaction or raise an exception"""
assert self._first_reaction is not None
return self._first_reaction

Expand Down
4 changes: 2 additions & 2 deletions aizynthfinder/search/breadth_first/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def from_dict(

@property # type: ignore
def children(self) -> List[ReactionNode]: # type: ignore
""" Gives the reaction children nodes """
"""Gives the reaction children nodes"""
return self._children

@children.setter
Expand Down Expand Up @@ -220,7 +220,7 @@ def from_dict(

@property # type: ignore
def children(self) -> List[MoleculeNode]: # type: ignore
""" Gives the molecule children nodes """
"""Gives the molecule children nodes"""
return self._children

@children.setter
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/search/breadth_first/search_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def _find_mol_nodes(node):

@property
def mol_nodes(self) -> Sequence[MoleculeNode]: # type: ignore
""" Return the molecule nodes of the tree """
"""Return the molecule nodes of the tree"""
return self._mol_nodes

def one_iteration(self) -> bool:
Expand Down
28 changes: 14 additions & 14 deletions aizynthfinder/search/dfpn/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,32 @@ def __init__(self) -> None:

@property # type: ignore
def children(self) -> List[ReactionNode]: # type: ignore
""" Gives the reaction children nodes """
"""Gives the reaction children nodes"""
return self._children # type: ignore

@property
def closed(self) -> bool:
""" Return if the node is proven or disproven """
"""Return if the node is proven or disproven"""
return self.proven or self.disproven

@property
def proven(self) -> bool:
""" Return if the node is proven"""
"""Return if the node is proven"""
return self.pn == 0

@property
def disproven(self) -> bool:
""" Return if the node is disproven"""
"""Return if the node is disproven"""
return self.dn == 0

def explorable(self) -> bool:
""" Return if the node can be explored by the search algorithm"""
"""Return if the node can be explored by the search algorithm"""
return not (
self.closed or self.pn > self.pn_threshold or self.dn > self.dn_threshold
)

def reset(self) -> None:
""" Reset the thresholds """
"""Reset the thresholds"""
if self.closed or self.expandable:
return
for child in self._children:
Expand All @@ -65,7 +65,7 @@ def reset(self) -> None:
self.dn_threshold = BIG_INT

def update(self) -> None:
""" Update the proof and disproof numbers """
"""Update the proof and disproof numbers"""
raise NotImplementedError("Implement a child class")

def _set_disproven(self) -> None:
Expand Down Expand Up @@ -139,7 +139,7 @@ def prop(self) -> StrDict:
return {"solved": self.proven, "mol": self.mol}

def expand(self) -> None:
""" Expand the molecule by utilising an expansion policy """
"""Expand the molecule by utilising an expansion policy"""
self.expandable = False
reactions, priors = self._config.expansion_policy([self.mol])
self.tree.profiling["expansion_calls"] += 1
Expand Down Expand Up @@ -194,7 +194,7 @@ def promising_child(self) -> Optional[ReactionNode]:
return best_child

def update(self) -> None:
""" Update the proof and disproof numbers """
"""Update the proof and disproof numbers"""
func = all if self.parent is None else any
if func(child.proven for child in self._children):
self._set_proven()
Expand Down Expand Up @@ -277,7 +277,7 @@ def __init__(

@property # type: ignore
def children(self) -> List[MoleculeNode]: # type: ignore
""" Gives the molecule children nodes """
"""Gives the molecule children nodes"""
return self._children # type: ignore

@property
Expand All @@ -286,7 +286,7 @@ def prop(self) -> StrDict:

@property
def proven(self) -> bool:
""" Return if the node is proven """
"""Return if the node is proven"""
if self.expandable:
return False
if self.pn == 0:
Expand All @@ -295,15 +295,15 @@ def proven(self) -> bool:

@property
def disproven(self) -> bool:
""" Return if the node is disproven """
"""Return if the node is disproven"""
if self.expandable:
return False
if self.dn == 0:
return True
return any(child.disproven for child in self._children)

def expand(self) -> None:
""" Expand the node by creating nodes for each reactant """
"""Expand the node by creating nodes for each reactant"""
self.expandable = False
reactants = self.reaction.reactants[self.reaction.index]
self._children = [
Expand Down Expand Up @@ -331,7 +331,7 @@ def promising_child(self) -> Optional[MoleculeNode]:
return best_child

def update(self) -> None:
""" Update the proof and disproof numbers"""
"""Update the proof and disproof numbers"""
if all(child.proven for child in self._children):
self._set_proven()
return
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/search/dfpn/search_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __init__(self, config: Configuration, root_smiles: str = None) -> None:

@property
def mol_nodes(self) -> Sequence[MoleculeNode]: # type: ignore
""" Return the molecule nodes of the tree """
"""Return the molecule nodes of the tree"""
return self._mol_nodes

def one_iteration(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/search/mcts/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def parent(self) -> Optional["MctsNode"]:

@property
def state(self) -> MctsState:
""" Return the underlying state of the node """
"""Return the underlying state of the node"""
return self._state

def actions_to(self) -> List[RetroReaction]:
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/search/mcts/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def add_node(node):
return self._graph

def nodes(self) -> List[MctsNode]:
""" Return all the nodes in the search tree """
"""Return all the nodes in the search tree"""
return list(self.graph())

def one_iteration(self) -> bool:
Expand Down
4 changes: 2 additions & 2 deletions aizynthfinder/search/retrostar/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def from_dict(

@property # type: ignore
def children(self) -> List[ReactionNode]: # type: ignore
""" Gives the reaction children nodes """
"""Gives the reaction children nodes"""
return self._children

@children.setter
Expand Down Expand Up @@ -301,7 +301,7 @@ def from_dict(

@property # type: ignore
def children(self) -> List[MoleculeNode]: # type: ignore
""" Gives the molecule children nodes """
"""Gives the molecule children nodes"""
return self._children

@children.setter
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/search/retrostar/search_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def _find_mol_nodes(node):

@property
def mol_nodes(self) -> Sequence[MoleculeNode]: # type: ignore
""" Return the molecule nodes of the tree """
"""Return the molecule nodes of the tree"""
return self._mol_nodes

def one_iteration(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/training/make_false_products.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def main(optional_args: Optional[Sequence[str]] = None) -> None:
errors: List[str] = []
for new_df in methods[selected_method](library, config, errors):
if new_df is not None:
false_lib = false_lib.append(new_df, sort=False)
false_lib = pd.concat([false_lib, new_df])
progress_bar.update(1)
progress_bar.close()

Expand Down
2 changes: 1 addition & 1 deletion aizynthfinder/training/preprocess_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def main(optional_args: Optional[Sequence[str]] = None) -> None:
sep=config["csv_sep"],
)
false_dataset["true_product"] = 0
dataset = true_dataset.append(false_dataset, sort=False)
dataset = pd.concat([true_dataset, false_dataset])

if config["reaction_smiles_column"]:
dataset = split_reaction_smiles(dataset, config)
Expand Down

0 comments on commit ceaa9d8

Please sign in to comment.