WikiFileController.put uploads before storing the entity (#153). Since a file and its description page share one title, action=upload creates the page as a side effect, with empty wikitext and no jsondata slot.
Consequences:
Proposal
Use MediaWiki's upload stash, which separates accepting the bytes from publishing them to a title:
action=upload&stash=1 returns a filekey and creates no page
store_entity creates the page normally, with page.exists false and no policy override
action=upload&filekey=...&filename=... publishes onto the page that now exists, so text is ignored and nothing is rewritten
One content revision, the caller's overwrite untouched, no validator noise. Failure behaviour improves in both directions: a file the wiki refuses never reaches step 2, and if step 2 fails nothing is published and the stash expires on its own, needing no delete rights.
Effort
mwclient exposes no stash parameter. Site.post forwards to api(), which takes no files, so step 1 needs raw_call('api', data, files={'file': ...}) with manual result handling, roughly 15 lines mirroring Site.upload. Step 3 can use Site.upload(filekey=...) as is.
WikiFileController.putuploads before storing the entity (#153). Since a file and its description page share one title,action=uploadcreates the page as a side effect, with empty wikitext and nojsondataslot.Consequences:
puthas to forceoverwrite="replace remote"so the metadata lands on a page that exists but holds nothingError: UUID could not be determined from title ..., because it now meets an existing page withjsondata: NoneProposal
Use MediaWiki's upload stash, which separates accepting the bytes from publishing them to a title:
action=upload&stash=1returns afilekeyand creates no pagestore_entitycreates the page normally, withpage.existsfalse and no policy overrideaction=upload&filekey=...&filename=...publishes onto the page that now exists, sotextis ignored and nothing is rewrittenOne content revision, the caller's
overwriteuntouched, no validator noise. Failure behaviour improves in both directions: a file the wiki refuses never reaches step 2, and if step 2 fails nothing is published and the stash expires on its own, needing no delete rights.Effort
mwclient exposes no
stashparameter.Site.postforwards toapi(), which takes nofiles, so step 1 needsraw_call('api', data, files={'file': ...})with manual result handling, roughly 15 lines mirroringSite.upload. Step 3 can useSite.upload(filekey=...)as is.