Skip to content

Commit

Permalink
Bump to version 0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
kblomqvist committed Apr 16, 2017
2 parents 38cf1b1 + b2d5dde commit 91ae2d7
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 66 deletions.
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
# Withings CLI
[![Number of downloads during the last month](https://img.shields.io/pypi/dm/withings-cli.svg)](https://pypi.python.org/pypi/withings-cli/)

A simple way to query Withings API from command line.

```
withings query -v[VERSION] -s SERVICE -p PARAM VALUE -p PARAM VALUE ... USER
```

### Installation

```bash
pip install withings-cli
```

### Set your API key and secret

[Register as a Withings developer](https://oauth.withings.com/partner/add)
Expand Down Expand Up @@ -36,21 +47,18 @@ The following call should show mes details — if the above step was accomplishe
withings whois me
```

### Try query mes body measures
### Query mes body measures

```bash
withings query -v1 -s measure -p action getmeas me
```

See how the query format corresponds to
[Withings API reference](https://oauth.withings.com/api/doc)

```
withings query -v[VERSION] -s SERVICE -p NAME VALUE -p NAME VALUE ... USER
```
[Withings API reference](https://oauth.withings.com/api/doc#api-Measure-get_measure): `https://wbsapi.withings.net/measure?action=getmeas`

### Read help for more commands
### Read help for more commands and options

```bash
withings --help
withings query --help
```
92 changes: 33 additions & 59 deletions withings_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,34 @@
SOFTWARE.
"""

__version__ = '0.3'

import click
import pytoml as toml
import json
import webbrowser
import collections

from os import path
from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler

__version__ = '0.2'
try:
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
except ImportError:
# Fallback to Python 2
from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler

CONFIG_FILE = path.join(path.expanduser("~"), '.withings')
CONFIG_OPTIONS = ('apikey', 'apisecret')
from .config import CONFIG

CALLBACK_URI = ('localhost', 1337)
WITHINGS_API_URI = 'https://wbsapi.withings.net'
WITHINGS_OAUTH_URI = 'https://oauth.withings.com/account'

class CallbackHandler(BaseHTTPRequestHandler):

def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write("Withings-cli: you may close this tab.")
self.wfile.write('Withings-cli: you may close this tab.'.encode())
self.oauth.parse_authorization_response(self.path)

def log_message(self, format, *args):
return


def load_configs():
try:
with open(CONFIG_FILE, 'r') as file:
return toml.load(file)
except EnvironmentError:
return dict()
return # Silence log messages


@click.group()
Expand All @@ -68,37 +58,27 @@ def cli():


@cli.command()
@click.argument('opt', type=str)
@click.argument('option', type=str)
@click.argument('value', type=str)
def config(opt, value):
def config(option, value):
"""Configure Withings API key and secret.
For example, 'withings config apikey 77..cf379b'
"""
if opt not in CONFIG_OPTIONS:
click.echo("Invalid config: Not in {}".format(CONFIG_OPTIONS))
raise click.Abort()

configs = load_configs()
configs[opt] = value
with open(CONFIG_FILE, 'w') as file:
toml.dump(configs, file)

from os import chmod
chmod(CONFIG_FILE, 0o600)
CONFIG[option] = value


@cli.command()
@click.argument('user')
def add(user):
"""Authorize to access user information."""
from requests_oauthlib import OAuth1Session
configs = load_configs()
from .config import WITHINGS_OAUTH_URI, CALLBACK_URI

try:
oauth = OAuth1Session(
configs['apikey'],
configs['apisecret'],
CONFIG['apikey'],
CONFIG['apisecret'],
callback_uri='http://{}:{}'.format(*CALLBACK_URI)
)
except KeyError:
Expand All @@ -116,34 +96,24 @@ def add(user):
httpd.handle_request()

tokens = oauth.fetch_access_token(WITHINGS_OAUTH_URI + '/access_token')

if not 'users' in configs:
configs['users'] = dict()
configs['users'][user] = tokens
with open(CONFIG_FILE, 'w') as file:
toml.dump(configs, file)

CONFIG['users'][user] = tokens
click.echo('User \'{}\' has been added.'.format(user))


@cli.command()
def list():
"""Prints user list."""
configs = load_configs()
try:
for user in configs['users'].keys():
click.echo(user)
except KeyError:
pass
for user in CONFIG['users'].keys():
click.echo(user)


@cli.command()
@click.argument('user')
@click.option('--version', '-v', type=int, help='Withings API version.')
@click.option('--service', '-s', type=str, help='Withings API service.')
@click.option('--param', '-p', type=(str, str), multiple=True, help='Withings API service parameters.')
@click.option('--pp', is_flag=True, help='Pretty print results.')
@click.option('--debug', is_flag=True, help='Show request URI')
@click.option('--pp', is_flag=True, help='Pretty print query result.')
@click.option('--debug', is_flag=True, help='Show query URI.')
def query(user, version, service, param, pp, debug):
"""Runs API query for a given user.
Expand All @@ -152,29 +122,33 @@ def query(user, version, service, param, pp, debug):
"""
from sys import stderr
from requests_oauthlib import OAuth1Session
from .config import WITHINGS_API_URI

if version is 2:
uri = WITHINGS_API_URI + '/v2'
else:
uri = WITHINGS_API_URI
uri += "/{}".format(service)
uri += '/{}'.format(service)

configs = load_configs()
user = configs['users'][user]
try:
user = CONFIG['users'][user]
except KeyError:
click.echo('Unknown user \'{}\'.'.format(user))
raise click.Abort()

params = dict(param)
params['userid'] = user['userid']

oauth = OAuth1Session(
configs['apikey'],
configs['apisecret'],
CONFIG['apikey'],
CONFIG['apisecret'],
resource_owner_key=user['oauth_token'],
resource_owner_secret=user['oauth_token_secret'],
signature_type='query'
)

r = oauth.get(uri, params=params)
content = json.loads(r.content)
content = json.loads(r.content.decode())

if debug:
click.echo(r.url, file=stderr)
Expand Down
47 changes: 47 additions & 0 deletions withings_cli/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
MIT License
Copyright (c) 2017 Kim Blomqvist
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

from os import path
from os import chmod
import pytoml as toml

CALLBACK_URI = ('localhost', 1337)
WITHINGS_API_URI = 'https://wbsapi.withings.net'
WITHINGS_OAUTH_URI = 'https://oauth.withings.com/account'
CONFIG_FILE = path.join(path.expanduser("~"), '.withings')

try:
with open(CONFIG_FILE, 'r') as file:
CONFIG = toml.load(file)
except EnvironmentError:
CONFIG = dict()
CONFIG['users'] = dict()

def save_confile():
with open(CONFIG_FILE, 'w') as file:
toml.dump(CONFIG, file)
chmod(CONFIG_FILE, 0o600)

import atexit
atexit.register(save_confile)

0 comments on commit 91ae2d7

Please sign in to comment.