Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Mar 18, 2019. It is now read-only.

Commit 39cf1fd

Browse files
Merge pull request #39 from core-api/sessions
Sessions
2 parents 9dea145 + 35615e9 commit 39cf1fd

20 files changed

+490
-339
lines changed

coreapi/__init__.py

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,67 @@
11
# coding: utf-8
2-
from coreapi.codecs import CoreJSONCodec, HTMLCodec, PlainTextCodec, PythonCodec
3-
from coreapi.codecs import negotiate_encoder, negotiate_decoder
2+
from coreapi.codecs import BaseCodec, CoreJSONCodec, HTMLCodec, PlainTextCodec, PythonCodec
43
from coreapi.document import Array, Document, Link, Object, Error, required
5-
from coreapi.document import dotted_path_to_list
64
from coreapi.exceptions import ParseError, TransportError, ErrorMessage
7-
from coreapi.transport import transition
5+
from coreapi.sessions import Session
6+
from coreapi.transport import BaseTransport, HTTPTransport
87

98

10-
__version__ = '1.1.0'
9+
__version__ = '1.2.0'
1110
__all__ = [
12-
'CoreJSONCodec', 'HTMLCodec', 'PlainTextCodec', 'PythonCodec',
11+
'BaseCodec', 'CoreJSONCodec', 'HTMLCodec', 'PlainTextCodec', 'PythonCodec',
1312
'negotiate_encoder', 'negotiate_decoder',
1413
'Array', 'Document', 'Link', 'Object', 'Error', 'required',
15-
'dotted_path_to_list',
1614
'ParseError', 'NotAcceptable', 'TransportError', 'ErrorMessage',
17-
'HTTPTransport',
18-
'load', 'dump', 'get'
15+
'BaseTransport', 'HTTPTransport',
16+
'load', 'dump', 'get', 'get_default_session'
1917
]
2018

2119

20+
_default_session = Session(
21+
codecs=[CoreJSONCodec(), HTMLCodec(), PlainTextCodec()],
22+
transports=[HTTPTransport()]
23+
)
24+
25+
26+
def get_default_session():
27+
return _default_session
28+
29+
30+
def get_session(credentials):
31+
return Session(
32+
codecs=[CoreJSONCodec(), HTMLCodec(), PlainTextCodec()],
33+
transports=[HTTPTransport(credentials=credentials)]
34+
)
35+
36+
37+
def negotiate_encoder(accept=None):
38+
session = _default_session
39+
return session.negotiate_encoder(accept)
40+
41+
42+
def negotiate_decoder(content_type=None):
43+
session = _default_session
44+
return session.negotiate_decoder(content_type)
45+
46+
47+
def get(url):
48+
session = _default_session
49+
return session.get(url)
50+
51+
52+
def action(document, keys, **params):
53+
session = _default_session
54+
return session.action(document, keys, **params)
55+
56+
2257
def load(bytestring, content_type=None):
23-
codec = negotiate_decoder(content_type)
58+
session = _default_session
59+
codec = session.negotiate_decoder(content_type)
2460
return codec.load(bytestring)
2561

2662

2763
def dump(document, accept=None, **kwargs):
28-
codec = negotiate_encoder(accept)
64+
session = _default_session
65+
codec = session.negotiate_encoder(accept)
2966
content = codec.dump(document, **kwargs)
3067
return codec.media_type, content
31-
32-
33-
def get(url):
34-
return transition(url, 'follow')

coreapi/codecs/__init__.py

Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,11 @@
11
# coding: utf-8
2-
from __future__ import unicode_literals
3-
from collections import OrderedDict
4-
from coreapi.exceptions import ParseError, NotAcceptable
5-
from coreapi.codecs.html import HTMLCodec
2+
from coreapi.codecs.base import BaseCodec
63
from coreapi.codecs.corejson import CoreJSONCodec
4+
from coreapi.codecs.html import HTMLCodec
75
from coreapi.codecs.plaintext import PlainTextCodec
86
from coreapi.codecs.python import PythonCodec
97

108

119
__all__ = [
12-
'CoreJSONCodec', 'HTMLCodec', 'PlainTextCodec', 'PythonCodec',
13-
'negotiate_encoder', 'negotiate_decoder'
10+
'BaseCodec', 'CoreJSONCodec', 'HTMLCodec', 'PlainTextCodec', 'PythonCodec',
1411
]
15-
16-
17-
# Codec negotiation
18-
19-
def negotiate_decoder(content_type=None):
20-
"""
21-
Given the value of a 'Content-Type' header, return the appropriate
22-
codec registered to decode the request content.
23-
"""
24-
if content_type is None:
25-
return CoreJSONCodec()
26-
27-
content_type = content_type.split(';')[0].strip().lower()
28-
try:
29-
codec_class = REGISTERED_CODECS[content_type]
30-
except KeyError:
31-
raise ParseError(
32-
"Cannot parse unsupported content type '%s'" % content_type
33-
)
34-
35-
if not hasattr(codec_class, 'load'):
36-
raise ParseError(
37-
"Cannot parse content type '%s'. This implementation only "
38-
"supports rendering for that content." % content_type
39-
)
40-
41-
return codec_class()
42-
43-
44-
def negotiate_encoder(accept=None):
45-
"""
46-
Given the value of a 'Accept' header, return a two tuple of the appropriate
47-
content type and codec registered to encode the response content.
48-
"""
49-
if accept is None:
50-
key, codec_class = list(REGISTERED_CODECS.items())[0]
51-
return codec_class()
52-
53-
media_types = set([
54-
item.split(';')[0].strip().lower()
55-
for item in accept.split(',')
56-
])
57-
58-
for key, codec_class in REGISTERED_CODECS.items():
59-
if key in media_types:
60-
return codec_class()
61-
62-
for key, codec_class in REGISTERED_CODECS.items():
63-
if key.split('/')[0] + '/*' in media_types:
64-
return codec_class()
65-
66-
if '*/*' in media_types:
67-
key, codec_class = list(REGISTERED_CODECS.items())[0]
68-
return codec_class()
69-
70-
raise NotAcceptable()
71-
72-
73-
REGISTERED_CODECS = OrderedDict([
74-
('application/vnd.coreapi+json', CoreJSONCodec),
75-
('text/html', HTMLCodec)
76-
])
77-
78-
79-
ACCEPT_HEADER = 'application/vnd.coreapi+json, application/json'

coreapi/codecs/base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import itypes
2+
3+
4+
def _mark_as_not_implemented(method):
5+
# Mark the method as not implemented, for the purposes for determining
6+
# if a codec supports encoding only, decoding only, or both.
7+
method.not_implemented = True
8+
return method
9+
10+
11+
class BaseCodec(itypes.Object):
12+
media_type = None
13+
14+
@_mark_as_not_implemented
15+
def load(self, bytes, base_url=None):
16+
raise NotImplementedError() # pragma: nocover
17+
18+
@_mark_as_not_implemented
19+
def dump(self, document, **kwargs):
20+
raise NotImplementedError() # pragma: nocover

coreapi/codecs/corejson.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import unicode_literals
22
from collections import OrderedDict
3+
from coreapi.codecs.base import BaseCodec
34
from coreapi.compat import string_types, force_bytes, urlparse
45
from coreapi.compat import COMPACT_SEPARATORS, VERBOSE_SEPARATORS
56
from coreapi.document import Document, Link, Array, Object, Error, Field
@@ -200,7 +201,7 @@ def _primative_to_document(data, base_url=None):
200201
return data
201202

202203

203-
class CoreJSONCodec(object):
204+
class CoreJSONCodec(BaseCodec):
204205
media_type = 'application/vnd.coreapi+json'
205206

206207
def load(self, bytes, base_url=None):

coreapi/codecs/html.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import unicode_literals
2+
from coreapi.codecs.base import BaseCodec
23
from coreapi.compat import urlparse
34
from coreapi.document import Document, Link, Array, Object, Error
45
import jinja2
@@ -39,7 +40,7 @@ def _render_html(node, url=None, key=None, path=''):
3940
return template.render(node=node, render=_render_html, url=url, key=key, path=path)
4041

4142

42-
class HTMLCodec(object):
43+
class HTMLCodec(BaseCodec):
4344
media_type = 'text/html'
4445

4546
def dump(self, document, extra_css=None, **kwargs):

coreapi/codecs/plaintext.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import unicode_literals
2+
from coreapi.codecs.base import BaseCodec
23
from coreapi.document import Document, Link, Array, Object, Error
34
import click
45
import json
@@ -88,7 +89,7 @@ def _fields_to_plaintext(link, colorize=False):
8889
])
8990

9091

91-
class PlainTextCodec(object):
92+
class PlainTextCodec(BaseCodec):
9293
"""
9394
A plaintext representation of a Document, intended for readability.
9495
"""

coreapi/codecs/python.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import unicode_literals
2+
from coreapi.codecs.base import BaseCodec
23
from coreapi.document import Document, Link, Array, Object, Error
34

45

@@ -45,7 +46,7 @@ def _to_repr(node):
4546
return repr(node)
4647

4748

48-
class PythonCodec(object):
49+
class PythonCodec(BaseCodec):
4950
"""
5051
A Python representation of a Document, for use with '__repr__'.
5152
"""

coreapi/commandline.py

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import click
22
import coreapi
3+
import json
34
import os
45
import sys
56

@@ -8,8 +9,59 @@ class NoDocument(Exception):
89
pass
910

1011

12+
def dotted_path_to_list(doc, path):
13+
"""
14+
Given a document and a string dotted notation like 'rows.123.edit",
15+
return a list of keys,such as ['rows', 123, 'edit'].
16+
"""
17+
keys = path.split('.')
18+
active = doc
19+
for idx, key in enumerate(keys):
20+
# Coerce array lookups to integers.
21+
if isinstance(active, coreapi.Array):
22+
try:
23+
key = int(key)
24+
keys[idx] = key
25+
except:
26+
pass
27+
28+
# Descend through the document, so we can correctly identify
29+
# any nested array lookups.
30+
try:
31+
active = active[key]
32+
except (KeyError, IndexError, ValueError, TypeError):
33+
break
34+
return keys
35+
36+
37+
def get_credentials_path():
38+
directory = os.path.join(os.path.expanduser('~'), '.coreapi')
39+
if os.path.isfile(directory):
40+
os.remove(directory)
41+
os.mkdir(directory)
42+
elif not os.path.exists(directory):
43+
os.mkdir(directory)
44+
return os.path.join(directory, 'credentials.json')
45+
46+
1147
def get_store_path():
12-
return os.path.join(os.path.expanduser('~'), '.coreapi')
48+
directory = os.path.join(os.path.expanduser('~'), '.coreapi')
49+
if os.path.isfile(directory):
50+
os.remove(directory)
51+
os.mkdir(directory)
52+
elif not os.path.exists(directory):
53+
os.mkdir(directory)
54+
return os.path.join(directory, 'document.json')
55+
56+
57+
def get_session():
58+
path = get_credentials_path()
59+
if os.path.exists(path) and os.path.isfile(path):
60+
store = open(path, 'rb')
61+
credentials = json.loads(store)
62+
store.close()
63+
return coreapi.get_session(credentials)
64+
return coreapi.get_default_session()
1365

1466

1567
def write_to_store(doc):
@@ -51,17 +103,21 @@ def client(ctx, version):
51103
@click.command(help='Fetch a document from the given URL.')
52104
@click.argument('url')
53105
def get(url):
106+
coreapi = get_session()
54107
doc = coreapi.get(url)
55108
click.echo(dump_to_console(doc))
56109
write_to_store(doc)
57110

58111

59-
@click.command(help='Remove the current document.')
112+
@click.command(help='Remove the current document, and any stored credentials.')
60113
def clear():
61114
path = get_store_path()
62115
if os.path.exists(path):
63116
os.remove(path)
64-
click.echo('Document cleared.')
117+
path = get_credentials_path()
118+
if os.path.exists(path):
119+
os.remove(path)
120+
click.echo('Cleared.')
65121

66122

67123
@click.command(help='Display the current document, or element at the given PATH.')
@@ -77,7 +133,7 @@ def show(path):
77133
if len(path) > 1:
78134
click.echo('Too many arguments.')
79135
sys.exit(1)
80-
keys = coreapi.dotted_path_to_list(doc, path[0])
136+
keys = dotted_path_to_list(doc, path[0])
81137
for key in keys:
82138
doc = doc[key]
83139
if isinstance(doc, (bool, type(None))):
@@ -103,7 +159,8 @@ def action(path, fields):
103159
click.echo('No current document. Use `coreapi get` to fetch a document first.')
104160
return
105161

106-
doc = doc.action(path, **kwargs)
162+
coreapi = get_session()
163+
doc = coreapi.action(doc, path, **kwargs)
107164
click.echo(dump_to_console(doc))
108165
write_to_store(doc)
109166

0 commit comments

Comments
 (0)