#get your username
import os

uname = os.environ['JPY_USER']
# asks for your password. Make sure to save it as a variable, don't print it.
#see https://docs.python.org/3.1/library/getpass.html
import getpass

pw = getpass.getpass()
········
#from https://www.mediawiki.org/wiki/API:Edit/Editing_with_Python
#see also:
# - https://www.mediawiki.org/wiki/API:Login
# - https://www.mediawiki.org/wiki/API:Userinfo
# - https://www.mediawiki.org/wiki/API:Edit

import requests

username = uname
password = pw
baseurl = 'https://test.wikipedia.org/w/'
summary = 'bot hello'
message = 'More test API edits from PAWS'
title = 'User:Jtmorgan/sandbox'
#https://test.wikipedia.org/wiki/User:Jtmorgan/sandbox

#see
# - https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields
# - http://stackoverflow.com/questions/10606133/sending-user-agent-using-requests-library-in-python
headers={'User-Agent' : 'Testing API edits', 'From' : 'jmorgan@wikimedia.org'}

# Login request
payload = {'action': 'query', 'format': 'json', 'utf8': '', 'meta': 'tokens', 'type': 'login'}
r1 = requests.post(baseurl + 'api.php', data=payload)

# login confirm
login_token = r1.json()['query']['tokens']['logintoken']
payload = {'action': 'login', 'format': 'json', 'utf8': '', 'lgname': username, 'lgpassword': password, 'lgtoken': login_token}
r2 = requests.post(baseurl + 'api.php', data=payload, cookies=r1.cookies)

# get edit token2
params3 = '?format=json&action=query&meta=tokens&continue='
r3 = requests.get(baseurl + 'api.php' + params3, cookies=r2.cookies)
edit_token = r3.json()['query']['tokens']['csrftoken']

edit_cookie = r2.cookies.copy()
edit_cookie.update(r3.cookies)

# save action
payload = {'action': 'edit', 'assert': 'user', 'format': 'json', 'utf8': '', 'text': message,'summary': summary, 'title': title, 'token': edit_token}
r4 = requests.post(baseurl + 'api.php', data=payload, cookies=edit_cookie, headers=headers)

print (r4.text)
{"edit":{"result":"Success","pageid":93978,"title":"User:Jtmorgan/sandbox","contentmodel":"wikitext","nochange":""}}
#I should probably move to OAuth and MWAPI for this. See:
# - https://github.com/requests/requests-oauthlib/blob/master/docs/examples/mediawiki.rst
# - https://www.mediawiki.org/wiki/Extension:OAuth#Using_OAuth
# - https://www.mediawiki.org/wiki/Extension:OAuth/Usage#Obtaining_access:_The_OAuth_handshake
# - https://github.com/mediawiki-utilities/python-mwapi
# - https://github.com/mediawiki-utilities/python-mwoauth

Old or unused

import mwapi

session = mwapi.Session("https://test.wikipedia.org",
                        user_agent="Test editing with mwapi <jmorgan@wikimedia.org>")
doc = session.get(action='query', prop='revisions', titles='User talk:Jtmorgan/sandbox', 
                  rvlimit=5, rvprop=['user', 'ids', 'timestamp'], rvdir="older")
doc = session.get(action='query', meta='tokens')
doc
{'batchcomplete': '', 'query': {'tokens': {'csrftoken': '+\\'}}}
 
from mwoauth import ConsumerToken, Handshaker
from six.moves import input # For compatibility between python 2 and 3
from os import environ
# Consruct a "consumer" from the key/secret provided by MediaWiki
# import config
consumer_token = ConsumerToken(environ['ACCESS_KEY'], environ['ACCESS_SECRET'])
print(consumer_token)
# Construct handshaker with wiki URI and consumer
handshaker = Handshaker("https://en.wikipedia.org/w/index.php",
                        consumer_token)

# Step 1: Initialize -- ask MediaWiki for a temporary key/secret for user
redirect, request_token = handshaker.initiate()

# Step 2: Authorize -- send user to MediaWiki to confirm authorization
print("Point your browser to: %s" % redirect) #
response_qs = input("Response query string: ")

# Step 3: Complete -- obtain authorized key/secret for "resource owner"
access_token = handshaker.complete(request_token, response_qs)
print(str(access_token))

# Step 4: Identify -- (optional) get identifying information about the user
identity = handshaker.identify(access_token)
print("Identified as {username}.".format(**identity))
ConsumerToken(key='df0ecb8681e1f245f2b7544880990d0a', secret='1aeb1fc172d7332dd969eecf7c6fd77484597edd')
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-13-3a064976107a> in <module>()
     11 
     12 # Step 1: Initialize -- ask MediaWiki for a temporary key/secret for user
---> 13 redirect, request_token = handshaker.initiate()
     14 
     15 # Step 2: Authorize -- send user to MediaWiki to confirm authorization

/srv/paws/lib/python3.4/site-packages/mwoauth/handshaker.py in initiate(self, callback)
     69 
     70         """
---> 71         return initiate(self.mw_uri, self.consumer_token, callback=callback)
     72 
     73     def complete(self, request_token, response_qs):

/srv/paws/lib/python3.4/site-packages/mwoauth/functions.py in initiate(mw_uri, consumer_token, callback)
     91         raise Exception("Expected x-www-form-urlencoded response from " +
     92                         "MediaWiki, but got something else: " +
---> 93                         "{0}".format(repr(r.content)))
     94 
     95     elif b('oauth_token') not in credentials or \

Exception: Expected x-www-form-urlencoded response from MediaWiki, but got something else: b'Error: An error occurred in the OAuth protocol: Invalid consumer'
def get_token(self): #should be self-token?
    """
    Request an edit token.
    """
    response = requests.get(
        self.api_url_post,
        params={
            'action': "query",
            'meta': "tokens",
            'type': "csrf",
            'format': "json"
            },
        headers={'User-Agent': self.user_agent},
        auth=self.auth1       
        )
    doc = response.json()
    try:
        self.token = doc['query']['tokens']['csrftoken'] 
    except:
        self.token = None
#         return token  # raise error instead, log it!!!
def publish_to_wiki(page_path, edit_summ, text, sec_str = False): #should just be 'publish'? sec_str should be sec? 
    """
    Publishes text to a wikipage, as a bot. 

    Specify the edit comment, and (optionally) the output section.
    """
    api_params={
        'action': "edit",
        'title': page_path,
        'summary': edit_summ,
        'text': text,
        'bot': 1,
        'token': token,
        'format': "json"
        }
    if sec_str:
        api_params['section'] = sec_str
    else:
        pass

    try:
        response = requests.post(self.api_url_post, api_params, headers={'User-Agent': self.user_agent}, auth=self.auth1)
#             print(response.status_code)
#             print(response.json())
        #if the edit was failure, log it            
    except:
        print("post failed.")   #should be logged, not printed
    result = response.json()
#         print(result)
    return response.status_code, result['edit']['result']