LeMyst / WikibaseIntegrator

A Python module to manipulate data on a Wikibase instance (like Wikidata) through the MediaWiki Wikibase API and the Wikibase SPARQL endpoint.
MIT License
67 stars 14 forks source link

ActionIfExistis --> APPEND or ADD REFERENCE #607

Closed lubianat closed 8 months ago

lubianat commented 1 year ago

I have a situation where a bot adds a previously existing statement:

https://www.wikidata.org/w/index.php?title=Q10357327&diff=prev&oldid=1954324483&diffmode=source

I wanted some behaviour that both kept the past reference block and added a new one.

Do you know if that is possible?

Thanks!

LeMyst commented 1 year ago

Hello @lubianat

Can you share the code you use to add the reference ?

LeMyst commented 1 year ago
item = wbi.item.get('Q124264')
reference = Reference()
reference.add(datatypes.Item(prop_nr='P149', value='Q124264'))
item.claims.get('P63600')[0].references.add(reference=reference)

This work correctly for me.

  1. get the item
  2. create a new empty reference
  3. update the reference with wanted values
  4. add the new reference to the existing referenceS
lubianat commented 1 year ago

Thanks! I was not explicitly trying to add a new reference, but add new statements that could eventually be present.

It is basically

            open_targets_reference = Reference()
            open_targets_reference.add(
                datatypes.Item(prop_nr="P248", value="Q113138000")
            )
            open_targets_reference.add(
                datatypes.Time(
                    "+2023-08-14T00:00:00Z",
                    prop_nr="P813",
                )
            )
            claims_json = item.claims.get_json()
            for claim in claims_json:
                if claims_json[claim][0]["mainsnak"]["property"] == "P592":
                    chembl_id =
claims_json[claim][0]["mainsnak"]["datavalue"]["value"]

            open_targets_reference.add(
                datatypes.URL(
                    f"https://platform.opentargets.org/drug/{chembl_id}",
                    prop_nr="P854",
                )
            )
            all_references.add(open_targets_reference)
            # Update the item on Wikidata
            claim = datatypes.Item(
                prop_nr="P129",
                value=obj_wd,
                qualifiers=qualifiers,
                references=all_references,
            )

            item.claims.add(claim,
action_if_exists=ActionIfExists.APPEND_OR_REPLACE)

From https://github.com/lubianat/opentargets2wikidata/blob/master/src/add_linked_targets_to_wikidata.py Tiago

On Wed, Aug 16, 2023 at 5:33 AM Myst @.***> wrote:

item = wbi.item.get('Q124264') reference = Reference() reference.add(datatypes.Item(prop_nr='P149', value='Q124264')) item.claims.get('P63600')[0].references.add(reference=reference)

This work correctly for me.

  1. get the item
  2. create a new empty reference
  3. update the reference with wanted values
  4. add the new reference to the existing referenceS

— Reply to this email directly, view it on GitHub https://github.com/LeMyst/WikibaseIntegrator/issues/607#issuecomment-1680190484, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB4NC746TBR34BUGAC5ST5LXVSAXHANCNFSM6AAAAAA3RDO3WY . You are receiving this because you were mentioned.Message ID: @.***>

LeMyst commented 1 year ago

Maybe what you want to do is not possible at this moment with WikibaseIntegrator.

You can "merge" an existing claim (same value) with your claim. If you want to do this, you need to get the claim, update it and replace the existing. If you want to append a new claim (multiple claims with the same values) you can use the ActionIfExists.FORCE_APPEND.

Currently, the ActionIfExists.APPEND_OR_REPLACE replace the existing claim when the same value is found, it's what happens in your first message.

Maybe a ActionIfExists.APPEND_OR_MERGE will be a good way to do it, merge the references/qualifiers with the existing claim. It's what you want to do?

Edit: Maybe allow for a compare callback

lubianat commented 1 year ago

Yes, exactly!

It is a (low priority) feature request, but I think it might be useful for other people.

Thanks for the attention!

Em qua., 16 de ago. de 2023 11:12, Myst @.***> escreveu:

Maybe what you want to do is not possible at this moment with WikibaseIntegrator.

You can "merge" an existing claim (same value) with your claim. If you want to do this, you need to get the claim, update it and replace the existing. If you want to append a new claim (multiple claims with the same values) you can use the ActionIfExists.FORCE_APPEND.

Currently, the ActionIfExists.APPEND_OR_REPLACE replace the existing claim when the same value is found, it's what happens in your first message.

Maybe a ActionIfExists.APPEND_OR_MERGE will be a good way to do it, merge the references/qualifiers with the existing claim. It's what you want to do?

— Reply to this email directly, view it on GitHub https://github.com/LeMyst/WikibaseIntegrator/issues/607#issuecomment-1680696498, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB4NC7ZC3OQIZ7BRPFS5SO3XVTINZANCNFSM6AAAAAA3RDO3WY . You are receiving this because you were mentioned.Message ID: @.***>

lubianat commented 1 year ago

This is the code bit that controls how statements are added, right?

https://github.com/LeMyst/WikibaseIntegrator/blob/6cf9c270fb9f48265ecc63f036f1d6008db9ae38/wikibaseintegrator/wbi_fastrun.py#L209

Is there any other place?

I might try and implement this myself

LeMyst commented 1 year ago

Instead you are using fastrun (I highly doubt), it's more likely this line you search:

https://github.com/LeMyst/WikibaseIntegrator/blob/6cf9c270fb9f48265ecc63f036f1d6008db9ae38/wikibaseintegrator/models/claims.py#L85

lubianat commented 1 year ago

By the way, I've implemented ActionIfExists.MERGE_REFS_OR_APPEND, I'll open a pull request with the changes so we can iterate from there :) Ok for you, @LeMyst ?

image

Here is the snippet:

                elif action_if_exists == ActionIfExists.MERGE_REFS_OR_APPEND:
                    claim_exists = False
                    for existing_claim in self.claims[property]:
                        existing_claim_json = existing_claim.get_json()
                        claim_to_add_json = claim.get_json()
                        # Check if the value of the claim exists
                        if (
                            claim_to_add_json["mainsnak"]["datavalue"]["value"]
                            == existing_claim_json["mainsnak"]["datavalue"]["value"]
                        ):
                            claim_exists = True
                            # Check if the references are identical
                            if not Claim.refs_equal(claim, existing_claim):
                                # If they're different, add the new reference block
                                for ref_to_add in claim.references:
                                    existing_claim.references.add(ref_to_add)

                            break

                    # If the claim value does not exist, append it
                    if not claim_exists:
                        self.claims[property].append(claim)
dpriskorn commented 8 months ago

I ran into this issue today, see https://github.com/dpriskorn/WikidataEurLexScraper/issues/2