napper

A ReST client created by Yann Kaiser (me)

Me

CS student at EFREI ; SE Intern at Criteo

https://github.com/epsy

clize:

def hello_world(name=None, *, no_capitalize=False):
$ python hello.py dave --no-capitalize

So what's napper?

Or rather, what is it not?

urllib

A.K.A. urlib2, urllib.request, six.moves.urllib.request


passwords = urllib.request.HTTPPasswordMgrWithPriorAuth()
passwords.add_password("reddit", "https://www.reddit.com/",
                       CLIENT_ID, CLIENT_SECRET,
                       is_authenticated=True)
opener = urllib.request.build_opener(
    urllib.request.HTTPBasicAuthHandler(passwords))
opener.addheaders = [('User-agent', 'A urllib example/0.1')]

if not access_token:
    r = opener.open(
        "https://www.reddit.com/api/v1/access_token",
        urllib.parse.urlencode({
            'grant_type': 'authorization_code',
            'code': USER_CODE,
            'redirect_uri': REDIR_URL,
        }).encode('utf8'))

    with r:
        doc = json.load(io.TextIOWrapper(r, 'utf8'))
        print(doc)
        access_token = doc['access_token']
opener.addheaders.append(("Authorization", "bearer " + access_token))

msgs = opener.open("https://oauth.reddit.com/message/sent?limit=1")
print(msgs.read().decode('utf8'))
						

requests

A.K.A. Phew, I don't actually have to use urllib


session = requests.Session()
session.headers['User-agent'] = "requests example/0.1"

if not access_token:
    r = session.post(
        "https://www.reddit.com/api/v1/access_token",
        { 'grant_type': 'authorization_code', 'code': USER_CODE,
          'redirect_uri': REDIR_URL },
        auth=(CLIENT_ID, CLIENT_SECRET))
    doc = r.json()
    access_token = doc['access_token']
session.headers['Authorization'] = "bearer " + access_token

r = session.get("https://oauth.reddit.com/message/sent?limit=1")
for msg in r.json()['data']['children']:
    msgdata = msg['data']
    print(msgdata["subject"], "\n", msgdata["body"])
						

aiohttp

A.K.A. Hey I can use asyncio now!


session = aiohttp.ClientSession(headers={'User-agent': "aiohttp example/0.1"})

async def req():
    global access_token
    if not access_token:
        r = await session.post(
            "https://www.reddit.com/api/v1/access_token",
            { 'grant_type': 'authorization_code', 'code': USER_CODE,
              'redirect_uri': REDIR_URL })
        doc = await r.json()
        access_token = doc['access_token']
    session._default_headers['Authorization'] = "bearer " + access_token

    r = await session.get("https://oauth.reddit.com/message/sent?limit=1")
    for msg in (await r.json())['data']['children']:
        msgdata = msg['data']
        print(msgdata["subject"], "\n", msgdata["body"])

with session:
    asyncio.get_event_loop().run_until_complete(req())
						

No really, what is it?

It specializes in ReST HTTP requests

ReST to Python mapper

Python ⇒ Need to use a pun

ReST ≡ to rest ≡ to (take a) nap

nap + mapper = napper

Get a cookie from httpbin.org


from napper import SessionFactory

httpbin = SessionFactory.from_address('http://httpbin.org/')

async def using_httpbin():
    with httpbin() as site:
        # GET http://httpbin.org/cookies/set?spam=ham
        print(await site.cookies.set.get(spam='ham'))
        # GET http://httpbin.org/cookies
        print(await site.cookies.get())

asyncio.get_event_loop().run_until_complete(using_httpbin())
						

Example: Reading a sent private message from reddit


from napper.apis import reddit

async def napper_example():
    async with reddit() as site:
        async for msg in site.message.sent.get(limit=1):
            print(msg["subject"], "\n", msg["body"])

asyncio.get_event_loop().run_until_complete(napper_example())
						

Show the most popular repository of "gist" authors


from napper.apis import github

async def getstargazers():
    with github() as site:
        async for gist in site.gists.get():
            try:
                repo = await gist.owner.repos_url.get()[0]
            except AttributeError, IndexError:
                pass # No owner or no repos
            print("{0.owner.login} {1.name} {1.stargazers_count}"
                  .format(gist, repo))

asyncio.get_event_loop().run_until_complete(getstargazers())
						

The Bad News

It's in alpha stage

It's for Python 3.5+ only

It's not documented yet

The Good News

It's in alpha stage

It's for Python 3.5+ only

It's easy to use anyway

What I'd still like to add

The "login" workflow

WebSocket support

Handling of dripping responses

XML support?

Web hook/callback support?

You tell me!

napper

python3.5 -m pip install --user napper

Source: https://github.com/epsy/napper

Slides: https://epsy.github.io/napper/

Chat: https://gitter.im/epsy/napper

Questions?