Ejemplo n.º 1
0
    def update_targets(self, items: List[List[Dict]]):
        """
        Inserts the new task_types into the task_types collection

        Args:
            items ([([dict],[int])]): A list of tuples of materials to update and the corresponding
                processed task_ids
        """

        items = list(filter(None, chain.from_iterable(items)))

        for item in items:
            item.update({"_bt": self.timestamp})

        material_ids = list({item["material_id"] for item in items})

        if len(items) > 0:
            self.logger.info(f"Updating {len(items)} materials")
            self.materials.remove_docs({self.materials.key: {"$in": material_ids}})
            self.materials.update(
                docs=jsanitize(items, allow_bson=True),
                key=["material_id"],
            )
        else:
            self.logger.info("No items to update")
Ejemplo n.º 2
0
    def update_targets(self, items):
        """
        Inserts the thermo docs into the thermo collection
        Args:
            items ([[dict]]): a list of list of thermo dictionaries to update
        """
        # flatten out lists
        items = list(filter(None, chain.from_iterable(items)))
        # Check if already updated this run
        items = [
            i for i in items if i[self.thermo.key] not in self._completed_tasks
        ]

        self._completed_tasks |= {i[self.thermo.key] for i in items}

        for item in items:
            if isinstance(item["last_updated"], dict):
                item["last_updated"] = MontyDecoder().process_decoded(
                    item["last_updated"])

        if len(items) > 0:
            self.logger.info(f"Updating {len(items)} thermo documents")
            self.thermo.update(docs=jsanitize(items), key=[self.thermo.key])
        else:
            self.logger.info("No items to update")
Ejemplo n.º 3
0
    def process_item(self, item) -> Dict:
        """
        - Add volume information to each entry to create the insertion electrode document
        - Add the host structure
        """
        if item is None:
            return None
        self.logger.debug(
            f"Working on {item['group_id']} with {len(item['thermo_docs'])}")

        entries = [
            tdoc_["entries"][tdoc_["energy_type"]]
            for tdoc_ in item["thermo_docs"]
        ]
        entries = list(map(ComputedStructureEntry.from_dict, entries))

        working_ion_entry = ComputedEntry.from_dict(
            item["working_ion_doc"]["entries"][item["working_ion_doc"]
                                               ["energy_type"]])
        working_ion = working_ion_entry.composition.reduced_formula

        decomp_energies = {
            d_["material_id"]: d_["energy_above_hull"]
            for d_ in item["thermo_docs"]
        }

        least_wion_ent = min(
            entries,
            key=lambda x: x.composition.get_atomic_fraction(working_ion))
        host_structure = least_wion_ent.structure.copy()
        host_structure.remove_species([item["working_ion"]])

        for ient in entries:
            ient.data["volume"] = ient.structure.volume
            ient.data["decomposition_energy"] = decomp_energies[ient.entry_id]

        ie = InsertionElectrodeDoc.from_entries(
            grouped_entries=entries,
            working_ion_entry=working_ion_entry,
            battery_id=item["group_id"],
            host_structure=host_structure,
        )
        if ie is None:
            return None  # {"failed_reason": "unable to create InsertionElectrode document"}
        return jsanitize(ie.dict())
Ejemplo n.º 4
0
def test_jsanitize():
    """
    Tests emmet Jsanitize which converts MSONable classes into dicts
    """
    # clean_json should have no effect on None types.
    d = {"hello": 1, "world": None}
    clean = jsanitize(d)
    assert clean["world"] is None
    assert json.loads(json.dumps(d)) == json.loads(json.dumps(clean))

    d = {"hello": GoodMSONClass(1, 2, 3)}
    with pytest.raises(TypeError):
        json.dumps(d)

    clean = jsanitize(d)
    assert isinstance(clean["hello"], dict)
    clean_strict = jsanitize(d, strict=True)
    assert clean_strict["hello"]["a"] == 1
    assert clean_strict["hello"]["b"] == 2

    d = {"dt": datetime.datetime.now()}
    clean = jsanitize(d)
    assert isinstance(clean["dt"], str)
    clean = jsanitize(d, allow_bson=True)
    assert isinstance(clean["dt"], datetime.datetime)

    d = {
        "a": ["b", np.array([1, 2, 3])],
        "b": ObjectId.from_datetime(datetime.datetime.now()),
    }
    clean = jsanitize(d)
    assert clean["a"] == ["b", [1, 2, 3]]
    assert isinstance(clean["b"], str)

    rnd_bin = bytes(np.random.rand(10))
    d = {"a": bytes(rnd_bin)}
    clean = jsanitize(d, allow_bson=True)
    assert clean["a"] == bytes(rnd_bin)
    assert isinstance(clean["a"], bytes)
Ejemplo n.º 5
0
    def _post_resource(
        self,
        body: Dict = None,
        params: Optional[Dict] = None,
        monty_decode: bool = True,
        suburl: Optional[str] = None,
        use_document_model: Optional[bool] = True,
    ):
        """
        Post data to the endpoint for a Resource.

        Arguments:
            body: body json to send in post request
            params: extra params to send in post request
            monty_decode: Decode the data using monty into python objects
            suburl: make a request to a specified sub-url
            use_document_model: whether to use the core document model for data reconstruction

        Returns:
            A Resource, a dict with two keys, "data" containing a list of documents, and
            "meta" containing meta information, e.g. total number of documents
            available.
        """

        check_limit()

        payload = jsanitize(body)

        try:
            url = self.endpoint
            if suburl:
                url = urljoin(self.endpoint, suburl)
                if not url.endswith("/"):
                    url += "/"
            response = self.session.post(url,
                                         json=payload,
                                         verify=True,
                                         params=params)

            if response.status_code == 200:

                if monty_decode:
                    data = json.loads(response.text, cls=MontyDecoder)
                else:
                    data = json.loads(response.text)

                if self.document_model and use_document_model:
                    data["data"] = [
                        self.document_model.parse_obj(d) for d in data["data"]
                    ]  # type: ignore

                return data

            else:
                try:
                    data = json.loads(response.text)["detail"]
                except (JSONDecodeError, KeyError):
                    data = "Response {}".format(response.text)
                if isinstance(data, str):
                    message = data
                else:
                    try:
                        message = ", ".join(
                            "{} - {}".format(entry["loc"][1], entry["msg"])
                            for entry in data)
                    except (KeyError, IndexError):
                        message = str(data)

                raise MPRestError(
                    f"REST post query returned with error status code {response.status_code} "
                    f"on URL {response.url} with message:\n{message}")

        except RequestException as ex:

            raise MPRestError(str(ex))