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

Commit ae66a0e

Browse files
committed
Merge pull request #50 from core-api/history
Added history
2 parents eec37eb + f5dfb85 commit ae66a0e

File tree

7 files changed

+391
-32
lines changed

7 files changed

+391
-32
lines changed

coreapi/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22
from coreapi.codecs import BaseCodec, CoreJSONCodec, HTMLCodec, PlainTextCodec, PythonCodec
33
from coreapi.document import Array, Document, Link, Object, Error, required
44
from coreapi.exceptions import ParseError, TransportError, ErrorMessage
5+
from coreapi.history import History
56
from coreapi.sessions import Session
67
from coreapi.transport import BaseTransport, HTTPTransport
78

89

9-
__version__ = '1.4.3'
10+
__version__ = '1.5.0'
1011
__all__ = [
1112
'BaseCodec', 'CoreJSONCodec', 'HTMLCodec', 'PlainTextCodec', 'PythonCodec',
1213
'negotiate_encoder', 'negotiate_decoder',
1314
'Array', 'Document', 'Link', 'Object', 'Error', 'required',
1415
'ParseError', 'NotAcceptable', 'TransportError', 'ErrorMessage',
15-
'BaseTransport', 'HTTPTransport',
16+
'BaseTransport', 'HTTPTransport', 'Session', 'History',
1617
'load', 'dump', 'get', 'get_default_session'
1718
]
1819

@@ -54,6 +55,11 @@ def action(document, keys, params=None, action=None, inplace=None):
5455
return session.action(document, keys, params, action=action, inplace=inplace)
5556

5657

58+
def reload(document):
59+
session = _default_session
60+
return session.reload(document)
61+
62+
5763
def load(bytestring, content_type=None):
5864
session = _default_session
5965
codec = session.negotiate_decoder(content_type)

coreapi/commandline.py

Lines changed: 128 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
config_path = os.path.join(os.path.expanduser('~'), '.coreapi')
99

10-
store_path = os.path.join(config_path, 'document.json')
10+
document_path = os.path.join(config_path, 'document.json')
11+
history_path = os.path.join(config_path, 'history.json')
1112
credentials_path = os.path.join(config_path, 'credentials.json')
1213
headers_path = os.path.join(config_path, 'headers.json')
1314
bookmarks_path = os.path.join(config_path, 'bookmarks.json')
@@ -46,23 +47,23 @@ def get_session():
4647
return coreapi.get_session(credentials, headers)
4748

4849

49-
def read_from_store():
50-
if not os.path.exists(store_path):
50+
def get_document():
51+
if not os.path.exists(document_path):
5152
return None
52-
store = open(store_path, 'rb')
53+
store = open(document_path, 'rb')
5354
content = store.read()
5455
store.close()
5556
return coreapi.load(content)
5657

5758

58-
def write_to_store(doc):
59+
def set_document(doc):
5960
content_type, content = coreapi.dump(doc)
60-
store = open(store_path, 'wb')
61+
store = open(document_path, 'wb')
6162
store.write(content)
6263
store.close()
6364

6465

65-
def dump_to_console(doc):
66+
def display(doc):
6667
codec = coreapi.codecs.PlainTextCodec()
6768
return codec.dump(doc, colorize=True)
6869

@@ -91,24 +92,33 @@ def client(ctx, version):
9192
@click.argument('url')
9293
def get(url):
9394
session = get_session()
95+
history = get_history()
9496
doc = session.get(url)
95-
click.echo(dump_to_console(doc))
96-
write_to_store(doc)
97+
history = history.add(doc)
98+
click.echo(display(doc))
99+
set_document(doc)
100+
set_history(history)
97101

98102

99-
@click.command(help='Remove the current document, and any stored credentials.')
103+
@click.command(help='Clear the active document and other state.\n\nThis includes the current document, history, credentials, headers and bookmarks.')
100104
def clear():
101-
if os.path.exists(store_path):
102-
os.remove(store_path)
103-
if os.path.exists(credentials_path):
104-
os.remove(credentials_path)
105+
for path in [
106+
document_path,
107+
history_path,
108+
credentials_path,
109+
headers_path,
110+
bookmarks_path
111+
]:
112+
if os.path.exists(path):
113+
os.remove(path)
114+
105115
click.echo('Cleared.')
106116

107117

108-
@click.command(help='Display the current document, or element at the given PATH.')
118+
@click.command(help='Display the current document.\n\nOptionally display just the element at the given PATH.')
109119
@click.argument('path', nargs=-1)
110120
def show(path):
111-
doc = read_from_store()
121+
doc = get_document()
112122
if doc is None:
113123
click.echo('No current document. Use `coreapi get` to fetch a document first.')
114124
return
@@ -119,13 +129,13 @@ def show(path):
119129
doc = doc[key]
120130
if isinstance(doc, (bool, type(None))):
121131
doc = {True: 'true', False: 'false', None: 'null'}[doc]
122-
click.echo(dump_to_console(doc))
132+
click.echo(display(doc))
123133

124134

125135
def validate_params(ctx, param, value):
126136
if any(['=' not in item for item in value]):
127137
raise click.BadParameter('Parameters need to be in format <field name>=<value>')
128-
return value
138+
return dict([tuple(item.split('=', 1)) for item in param])
129139

130140

131141
def validate_inplace(ctx, param, value):
@@ -136,7 +146,7 @@ def validate_inplace(ctx, param, value):
136146
return value.lower() == 'true'
137147

138148

139-
@click.command(help='Interact with the current document, given a PATH to a link.')
149+
@click.command(help='Interact with the active document.\n\nRequires a PATH to a link in the document.')
140150
@click.argument('path', nargs=-1)
141151
@click.option('--param', '-p', multiple=True, callback=validate_params, help='Parameter in the form <field name>=<value>.')
142152
@click.option('--action', '-a', help='Set the link action explicitly.', default=None)
@@ -146,18 +156,35 @@ def action(path, param, action, inplace):
146156
click.echo('Missing PATH to a link in the document.')
147157
sys.exit(1)
148158

149-
params = dict([tuple(item.split('=', 1)) for item in param])
150-
151-
doc = read_from_store()
159+
doc = get_document()
152160
if doc is None:
153161
click.echo('No current document. Use `coreapi get` to fetch a document first.')
154162
return
155163

156164
session = get_session()
165+
history = get_history()
157166
keys = coerce_key_types(doc, path)
158-
doc = session.action(doc, keys, params=params, action=action, inplace=inplace)
159-
click.echo(dump_to_console(doc))
160-
write_to_store(doc)
167+
doc = session.action(doc, keys, params=param, action=action, inplace=inplace)
168+
history = history.add(doc)
169+
click.echo(display(doc))
170+
set_document(doc)
171+
set_history(history)
172+
173+
174+
@click.command(help='Reload the current document.')
175+
def reload_document():
176+
doc = get_document()
177+
if doc is None:
178+
click.echo('No current document. Use `coreapi get` to fetch a document first.')
179+
return
180+
181+
session = get_session()
182+
history = get_history()
183+
doc = session.reload(doc)
184+
history = history.add(doc)
185+
click.echo(display(doc))
186+
set_document(doc)
187+
set_history(history)
161188

162189

163190
# Credentials
@@ -177,7 +204,7 @@ def set_credentials(credentials):
177204
store.close
178205

179206

180-
@click.group(help='Configure credentials using in request "Authorization:" headers.')
207+
@click.group(help='Configure request credentials. Request credentials are associated with a given domain, and used in request "Authorization:" headers.')
181208
def credentials():
182209
pass
183210

@@ -309,13 +336,13 @@ def bookmarks_show():
309336

310337
click.echo(click.style('Bookmarks', bold=True))
311338
for key, value in sorted(bookmarks.items()):
312-
click.echo(fmt.format(name=key, title=value['title'] or 'Document', url=value['url']))
339+
click.echo(fmt.format(name=key, title=value['title'] or 'Document', url=json.dumps(value['url'])))
313340

314341

315342
@click.command(help="Add the current document to the bookmarks, with the given NAME.")
316343
@click.argument('name', nargs=1)
317344
def bookmarks_add(name):
318-
doc = read_from_store()
345+
doc = get_document()
319346
if doc is None:
320347
click.echo('No current document.')
321348
return
@@ -349,14 +376,80 @@ def bookmarks_get(name):
349376
return
350377

351378
session = get_session()
379+
history = get_history()
352380
doc = session.get(bookmark['url'])
353-
click.echo(dump_to_console(doc))
354-
write_to_store(doc)
381+
history = history.add(doc)
382+
click.echo(display(doc))
383+
set_document(doc)
384+
set_history(history)
385+
386+
387+
# History
388+
389+
def get_history():
390+
if not os.path.isfile(history_path):
391+
return coreapi.History(max_items=20)
392+
history_file = open(history_path, 'rb')
393+
bytestring = history_file.read()
394+
history_file.close()
395+
return coreapi.history.load_history(bytestring)
396+
397+
398+
def set_history(history):
399+
bytestring = coreapi.history.dump_history(history)
400+
history_file = open(history_path, 'wb')
401+
history_file.write(bytestring)
402+
history_file.close()
403+
404+
405+
@click.group(help="Navigate the browser history.")
406+
def history():
407+
pass
408+
409+
410+
@click.command(help="List the browser history.")
411+
def history_show():
412+
history = get_history()
413+
414+
click.echo(click.style('History', bold=True))
415+
for is_active, doc in history.get_items():
416+
prefix = '[*] ' if is_active else '[ ] '
417+
document = 'blank' if (doc is None) else '<%s %s>' % (doc.title, json.dumps(doc.url))
418+
click.echo(prefix + document)
419+
420+
421+
@click.command(help="Navigate back through the browser history.")
422+
def history_back():
423+
session = get_session()
424+
history = get_history()
425+
if history.is_at_oldest:
426+
click.echo("Currently at oldest point in history. Cannot navigate back.")
427+
return
428+
doc, history = history.back()
429+
doc = session.reload(doc)
430+
click.echo(display(doc))
431+
set_history(history)
432+
set_document(doc)
433+
434+
435+
@click.command(help="Navigate forward through the browser history.")
436+
def history_forward():
437+
session = get_session()
438+
history = get_history()
439+
if history.is_at_most_recent:
440+
click.echo("Currently at most recent point in history. Cannot navigate forward.")
441+
return
442+
doc, history = history.forward()
443+
doc = session.reload(doc)
444+
click.echo(display(doc))
445+
set_history(history)
446+
set_document(doc)
355447

356448

357449
client.add_command(get)
358450
client.add_command(show)
359451
client.add_command(action)
452+
client.add_command(reload_document, name='reload')
360453
client.add_command(clear)
361454

362455
client.add_command(credentials)
@@ -375,6 +468,11 @@ def bookmarks_get(name):
375468
bookmarks.add_command(bookmarks_remove, name='remove')
376469
bookmarks.add_command(bookmarks_show, name='show')
377470

471+
client.add_command(history)
472+
history.add_command(history_back, name='back')
473+
history.add_command(history_forward, name='forward')
474+
history.add_command(history_show, name='show')
475+
378476

379477
if __name__ == '__main__':
380478
client()

coreapi/document.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ def __repr__(self):
9090
def __str__(self):
9191
return _str(self)
9292

93+
def __eq__(self, other):
94+
if isinstance(other, Document):
95+
return (
96+
self.url == other.url and
97+
self.title == other.title and
98+
self._data == other._data
99+
)
100+
return super(Document, self).__eq__(other)
101+
93102
@property
94103
def url(self):
95104
return self._url

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy