Completed
Push — master ( c4c141...16569e )
by Chris
01:28
created

shared_data()   A

Complexity

Conditions 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
1
"""A separate Flask app that serves fake endpoints for demo purposes."""
2
3
# -*- coding: utf-8 -*-
4
5
from itertools import combinations
6
import json
7
import locale
8
import os
9
from datetime import timedelta as td
10
from datetime import datetime as dt
11
from random import randrange as rr
12
from random import choice, random
13
import time
14
15
from flask import (
16
    Flask,
17
    abort,
18
    request,
19
    jsonify,
20
    render_template,
21
)
22
from flask_cors import CORS
23
from flask_cors import cross_origin
24
25
app = Flask('endpoints_test')
26
CORS(app)
27
app.config['SECRET_KEY'] = 'NOTSECURELOL'
28
app.debug = True
29
30
STRESS_MAX_POINTS = 300
31
32
locale.setlocale(locale.LC_ALL, '')
33
34
cwd = os.getcwd()
35
36
37
def recursive_d3_data(current=0, max_iters=12, data=None):
38
    """Generate d3js data for stress testing.
39
    Format is suitable in treemap, circlepack and dendrogram testing.
40
    """
41
    if current >= max_iters:
42
        return data
43
    if data is None:
44
        data = dict(name='foo', size=rr(10, 10000), children=[])
45
    data = dict(name='foo', size=rr(10, 10000),
46
                children=[data, data])
47
    return recursive_d3_data(
48
        current=current + 1,
49
        max_iters=max_iters,
50
        data=data)
51
52
53
def dates_list(max_dates=10):
54
    """Generate a timeseries dates list."""
55
    now = dt.now()
56
    return [str(now + td(days=i * 10))[0:10] for i in range(max_dates)]
57
58
59
def rr_list(max_range=10):
60
    """Generate a list of random integers."""
61
    return [rr(0, 100) for i in range(max_range)]
62
63
64
def rand_hex_color():
65
    """Generate a random hex color.
66
    e.g. #FF0000
67
    """
68
    chars = list('0123456789ABCDEF')
69
    return '#{0}{1}{2}{3}{4}{5}'.format(
70
        choice(chars),
71
        choice(chars),
72
        choice(chars),
73
        choice(chars),
74
        choice(chars),
75
        choice(chars),
76
    )
77
78
79
@cross_origin()
80
@app.route('/combination')
81
def combination():
82
    """Fake endpoint."""
83
    data = {
84
        'columns': [
85
            ['data1', 30, 20, 50, 40, 60, 50],
86
            ['data2', 200, 130, 90, 240, 130, 220],
87
            ['data3', 300, 200, 160, 400, 250, 250],
88
            ['data4', 200, 130, 90, 240, 130, 220],
89
            ['data5', 130, 120, 150, 140, 160, 150],
90
            ['data6', 90, 70, 20, 50, 60, 120],
91
        ],
92
        'type': 'bar',
93
        'types': {
94
            'data3': 'spline',
95
            'data4': 'line',
96
            'data6': 'area',
97
        },
98
        'groups': [
99
            ['data1', 'data2'],
100
        ]
101
    }
102
    return jsonify(dict(data=data))
103
104
105
@cross_origin()
106
@app.route('/timeseriesc3')
107
def timeseriesc3():
108
    """Fake endpoint."""
109
    return jsonify(dict(
110
        dates=[
111
            '19{}-{}-{}'.format(rr(10, 99), rr(10, 31), rr(10, 31))
112
            for _ in range(4)
113
        ],
114
        abc=rr_list(max_range=4),
115
        cde=rr_list(max_range=4),
116
    ))
117
118
119
@cross_origin()
120
@app.route('/stacked-bar')
121
def stackedbar():
122
    """Fake endpoint."""
123
    return jsonify({
124
        'data': {
125
            'columns': [
126
                ['data1', -30, 200, 200, 400, -150, 250],
127
                ['data2', 130, 100, -100, 200, -150, 50],
128
                ['data3', -230, 200, 200, -300, 250, 250]
129
            ],
130
            'type': 'bar',
131
            'groups': [
132
                ['data1', 'data2']
133
            ]
134
        },
135
        'grid': {
136
            'y': {
137
                'lines': [{'value': 0}]
138
            }
139
        }
140
    })
141
142
143
@cross_origin()
144
@app.route('/wordcloud')
145
def wordcloud():
146
    """Fake endpoint."""
147
    words = [
148
        'awesome', 'rad', 'neato', 'the', 'flask', 'jsondash', 'graphs',
149
        'charts', 'd3', 'js', 'dashboards', 'c3',
150
    ]
151
    sizes = range(len(words))
152
    data = [
153
        {
154
            'text': word,
155
            'size': sizes[i] * 12
156
        }
157
        for i, word in enumerate(words)
158
    ]
159
    return jsonify(data)
160
161
162
@cross_origin()
163
@app.route('/sigma')
164
def sigma():
165
    """Fake endpoint."""
166
    chart_name = request.args.get('name', 'basic')
167
    if chart_name == 'random':
168
        nodes = request.args.get('nodes', 'abcdefghij')
169
        _vertices = list(nodes)
170
        _edges = combinations(_vertices, 2)
171
        edges, vertices = [], []
172
        for (frm, to) in _edges:
173
            edges.append(dict(
174
                id='{}-{}'.format(frm, to),
175
                color=rand_hex_color(),
176
                source=frm,
177
                target=to,
178
                size=rr(1, 10),
179
                x=rr(1, 100),
180
                y=rr(1, 100),
181
            ))
182
        for vertex in _vertices:
183
            vertices.append(dict(
184
                id=vertex,
185
                size=rr(1, 10),
186
                x=rr(1, 100),
187
                y=rr(1, 100),
188
                color=rand_hex_color(),
189
                label='node {}'.format(vertex),
190
            ))
191
        data = dict(
192
            nodes=vertices,
193
            edges=edges,
194
        )
195
        return jsonify(data)
196
    filename = '{}/examples/sigma/{}.json'.format(cwd, chart_name)
197
    try:
198
        with open(filename, 'r') as chartjson:
199
            return chartjson.read()
200
    except IOError:
201
        pass
202
    return jsonify({})
203
204
205
@cross_origin()
206
@app.route('/cytoscape')
207
def cytoscape():
208
    """Fake endpoint.
209
210
    Reads data from a local cytoscape spec, and if there is a
211
    remote url specified, (assuming it exists here), open and load it as well.
212
213
    This returns all required json as a single endpoint.
214
    """
215
    chart_name = request.args.get('name', 'dagre')
216
    filename = '{}/examples/cytoscape/{}.json'.format(cwd, chart_name)
217
    try:
218
        with open(filename, 'r') as chartjson:
219
            return chartjson.read()
220
    except IOError:
221
        pass
222
    return jsonify({})
223
224
225
@cross_origin()
226
@app.route('/vegalite')
227
def vegalite():
228
    """Fake endpoint.
229
230
    Reads data from a local vega spec, and if there is a
231
    remote url specified, (assuming it exists here), open and load it as well.
232
233
    This returns all required json as a single endpoint.
234
    """
235
    chart_type = request.args.get('type', 'bar')
236
    filename = '{}/examples/vegalite/{}.json'.format(cwd, chart_type)
237
    try:
238
        with open(filename, 'r') as chartjson:
239
            chartjson = chartjson.read()
240
            data = json.loads(chartjson)
241
            if data.get('data', {}).get('url') is not None:
242
                datapath = '{}/examples/vegalite/{}'.format(
243
                    cwd, data['data']['url']
244
                )
245
                with open(datapath, 'r') as datafile:
246
                    if datapath.endswith('.json'):
247
                        raw_data = datafile.read()
248
                        raw_data = json.loads(raw_data)
249
                    # TODO: adding csv support for example.
250
                    data.update(data=dict(
251
                        name='some data',
252
                        values=raw_data,
253
                    ))
254
                    return jsonify(data)
255
            else:
256
                return chartjson
257
    except IOError:
258
        pass
259
    return jsonify({})
260
261
262
@cross_origin()
263
@app.route('/plotly')
264
def plotly():
265
    """Fake endpoint."""
266
    chart_type = request.args.get('chart', 'line')
267
    filename = '{}/examples/plotly/{}.json'.format(cwd, chart_type)
268
    with open(filename, 'r') as chartjson:
269
        return chartjson.read()
270
    return jsonify({})
271
272
273
@cross_origin
274
@app.route('/plotly-dynamic')
275
def plotly_dynamic():
276
    """Fake endpoint."""
277
    filename = '{}/examples/plotly/bar_line_dynamic.json'.format(cwd)
278
    with open(filename, 'r') as chartjson:
279
        return chartjson.read()
280
    return jsonify({})
281
282
283
@cross_origin()
284
@app.route('/timeline')
285
def timeline():
286
    """Fake endpoint."""
287
    with open('{}/examples/timeline3.json'.format(cwd), 'r') as timelinejson:
288
        return timelinejson.read()
289
    return jsonify({})
290
291
292
@app.route('/dtable', methods=['GET'])
293
def dtable():
294
    """Fake endpoint."""
295
    if 'stress' in request.args:
296
        return jsonify([
297
            dict(
298
                foo=rr(1, 1000),
299
                bar=rr(1, 1000),
300
                baz=rr(1, 1000),
301
                quux=rr(1, 1000)) for _ in range(STRESS_MAX_POINTS)
302
        ])
303
    fname = 'dtable-override' if 'override' in request.args else 'dtable'
304
    with open('{}/examples/{}.json'.format(os.getcwd(), fname), 'r') as djson:
305
        return djson.read()
306
    return jsonify({})
307
308
309
@cross_origin()
310
@app.route('/timeseries')
311
def timeseries():
312
    """Fake endpoint."""
313
    return jsonify({
314
        "dates": dates_list(),
315
        "line1": rr_list(max_range=10),
316
        "line2": rr_list(max_range=10),
317
        "line3": rr_list(max_range=10),
318
    })
319
320
321
@cross_origin()
322
@app.route('/custom')
323
def custompage():
324
    """Fake endpoint."""
325
    kwargs = dict(number=rr(1, 1000))
326
    return render_template('examples/custom.html', **kwargs)
327
328
329
@cross_origin()
330
@app.route('/gauge')
331
def gauge():
332
    """Fake endpoint."""
333
    return jsonify({'data': rr(1, 100)})
334
335
336
@cross_origin()
337
@app.route('/area-custom')
338
def area_custom():
339
    """Fake endpoint."""
340
    return jsonify({
341
        "data": {
342
            "columns": [
343
                ["data1", 300, 350, 300, 0, 0, 0],
344
                ["data2", 130, 100, 140, 200, 150, 50]
345
            ],
346
            "types": {
347
                "data1": "area",
348
                "data2": "area-spline"
349
            }
350
        }
351
    })
352
353
354
@cross_origin()
355
@app.route('/scatter')
356
def scatter():
357
    """Fake endpoint."""
358
    if 'override' in request.args:
359
        with open('{}/examples/overrides.json'.format(cwd), 'r') as jsonfile:
360
            return jsonfile.read()
361
    return jsonify({
362
        "bar1": [1, 2, 30, 12, 100],
363
        "bar2": rr_list(max_range=40),
364
        "bar3": rr_list(max_range=40),
365
        "bar4": [-10, 1, 5, 4, 10, 20],
366
    })
367
368
369
@cross_origin()
370
@app.route('/pie')
371
def pie():
372
    """Fake endpoint."""
373
    letters = list('abcde')
374
    if 'stress' in request.args:
375
        letters = range(STRESS_MAX_POINTS)
376
    return jsonify({'data {}'.format(name): rr(1, 100) for name in letters})
377
378
379
@cross_origin()
380
@app.route('/custom-inputs')
381
def custom_inputs():
382
    """Fake endpoint."""
383
    _range = int(request.args.get('range', 5))
384
    entries = int(request.args.get('entries', 3))
385
    starting = int(request.args.get('starting_num', 0))
386
    prefix = request.args.get('prefix', 'item')
387
    if 'override' in request.args:
388
        show_axes = request.args.get('show_axes', False)
389
        show_axes = show_axes == 'on'
390
        data = dict(
391
            data=dict(
392
                columns=[
393
                    ['{} {}'.format(prefix, i)] + rr_list(max_range=entries)
394
                    for i in range(starting, _range)
395
                ],
396
            )
397
        )
398
        if show_axes:
399
            data.update(axis=dict(
400
                x=dict(label='This is the X axis'),
401
                y=dict(label='This is the Y axis')))
402
        return jsonify(data)
403
    return jsonify({
404
        i: rr_list(max_range=_range) for i in range(starting, entries)
405
    })
406
407
408
@cross_origin()
409
@app.route('/bar')
410
def barchart():
411
    """Fake endpoint."""
412
    if 'stress' in request.args:
413
        return jsonify({
414
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
415
            for k in range(STRESS_MAX_POINTS)
416
        })
417
    return jsonify({
418
        "bar1": [1, 2, 30, 12, 100],
419
        "bar2": rr_list(max_range=5),
420
        "bar3": rr_list(max_range=5),
421
    })
422
423
424
@cross_origin()
425
@app.route('/line')
426
def linechart():
427
    """Fake endpoint."""
428
    if 'stress' in request.args:
429
        return jsonify({
430
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
431
            for k in range(STRESS_MAX_POINTS)
432
        })
433
    return jsonify({
434
        "line1": [1, 4, 3, 10, 12, 14, 18, 10],
435
        "line2": [1, 2, 10, 20, 30, 6, 10, 12, 18, 2],
436
        "line3": rr_list(),
437
    })
438
439
440
@cross_origin()
441
@app.route('/shared')
442
def shared_data():
443
    """Fake endpoint to demonstrate sharing data from one source."""
444
    letters = list('abcde')
445
    piedata = {'data {}'.format(name): rr(1, 100) for name in letters}
446
    bardata = {
447
        "bar1": [1, 2, 30, 12, 100],
448
        "bar2": rr_list(max_range=5),
449
        "bar3": rr_list(max_range=5),
450
    }
451
    linedata = {
452
        "line1": [1, 4, 3, 10, 12, 14, 18, 10],
453
        "line2": [1, 2, 10, 20, 30, 6, 10, 12, 18, 2],
454
        "line3": rr_list(),
455
    }
456
    return jsonify({
457
        'multicharts': {
458
            'line': linedata,
459
            'bar': bardata,
460
            'pie': piedata,
461
        }
462
    })
463
464
465
@cross_origin()
466
@app.route('/singlenum')
467
def singlenum():
468
    """Fake endpoint."""
469
    _min, _max = 10, 10000
470
    if 'sales' in request.args:
471
        val = locale.currency(float(rr(_min, _max)), grouping=True)
472
    else:
473
        val = rr(_min, _max)
474
    if 'negative' in request.args:
475
        val = '-{}'.format(val)
476
    return jsonify(data=val)
477
478
479
@cross_origin()
480
@app.route('/deadend')
481
def test_die():
482
    """Fake endpoint that ends in a random 50x error."""
483
    # Simulate slow connection
484
    sleep = request.args.get('sleep', True)
485
    if sleep != '':
486
        sleep_for = request.args.get('sleep_for')
487
        time.sleep(int(sleep_for) if sleep_for is not None else random())
488
    err_code = request.args.get('error_code')
489
    rand_err = choice([500, 501, 502, 503, 504])
490
    abort(int(err_code) if err_code is not None else rand_err)
491
492
493
@cross_origin()
494
@app.route('/venn')
495
def test_venn():
496
    """Fake endpoint."""
497
    data = [
498
        {'sets': ['A'], 'size': rr(10, 100)},
499
        {'sets': ['B'], 'size': rr(10, 100)},
500
        {'sets': ['C'], 'size': rr(10, 100)},
501
        {'sets': ['A', 'B'], 'size': rr(10, 100)},
502
        {'sets': ['A', 'B', 'C'], 'size': rr(10, 100)},
503
    ]
504
    return jsonify(data)
505
506
507
@cross_origin()
508
@app.route('/sparklines', methods=['GET'])
509
def sparklines():
510
    """Fake endpoint."""
511
    if any([
512
        'pie' in request.args,
513
        'discrete' in request.args,
514
    ]):
515
        return jsonify([rr(1, 100) for _ in range(10)])
516
    return jsonify([[i, rr(i, 100)] for i in range(10)])
517
518
519
@cross_origin()
520
@app.route('/circlepack', methods=['GET'])
521
def circlepack():
522
    """Fake endpoint."""
523
    if 'stress' in request.args:
524
        # Build a very large dataset
525
        return jsonify(recursive_d3_data())
526
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
527
        return djson.read()
528
    return jsonify({})
529
530
531
@cross_origin()
532
@app.route('/treemap', methods=['GET'])
533
def treemap():
534
    """Fake endpoint."""
535
    if 'stress' in request.args:
536
        # Build a very large dataset
537
        return jsonify(recursive_d3_data())
538
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
539
        return djson.read()
540
    return jsonify({})
541
542
543
@cross_origin()
544
@app.route('/map', methods=['GET'])
545
def datamap():
546
    """Fake endpoint."""
547
    return render_template('examples/map.html')
548
549
550
@cross_origin()
551
@app.route('/dendrogram', methods=['GET'])
552
def dendro():
553
    """Fake endpoint."""
554
    if 'stress' in request.args:
555
        # Build a very large dataset
556
        return jsonify(recursive_d3_data())
557
    filename = 'flare-simple' if 'simple' in request.args else 'flare'
558
    with open('{}/examples/{}.json'.format(cwd, filename), 'r') as djson:
559
        return djson.read()
560
    return jsonify({})
561
562
563
@cross_origin()
564
@app.route('/voronoi', methods=['GET'])
565
def voronoi():
566
    """Fake endpoint."""
567
    w, h = request.args.get('width', 800), request.args.get('height', 800)
568
    max_points = int(request.args.get('points', 100))
569
    if 'stress' in request.args:
570
        max_points = 500
571
    return jsonify([[rr(1, h), rr(1, w)] for _ in range(max_points)])
572
573
574
@cross_origin()
575
@app.route('/digraph', methods=['GET'])
576
def graphdata():
577
    """Fake endpoint."""
578
    if 'filetree' in request.args:
579
        with open('{}/examples/filetree_digraph.dot'.format(cwd), 'r') as dot:
580
            return jsonify(dict(graph=dot.read()))
581
    if 'simple' in request.args:
582
        graphdata = """
583
        digraph {
584
            a -> b;
585
            a -> c;
586
            b -> c;
587
            b -> a;
588
            b -> b;
589
        }
590
        """
591
        return jsonify(dict(graph=graphdata))
592
    nodes = list('abcdefghijkl')
593
    node_data = '\n'.join([
594
        '{0} -> {1};'.format(choice(nodes), choice(nodes))
595
        for _ in range(10)
596
    ])
597
    graphdata = """digraph {lb} {nodes} {rb}""".format(
598
        lb='{', rb='}', nodes=node_data)
599
    return jsonify(dict(
600
        graph=graphdata,
601
    ))
602
603
604
if __name__ == '__main__':
605
    PORT = int(os.getenv('PORT', 5004))
606
    HOST = os.getenv('HOST', '0.0.0.0')
607
    app.run(debug=True, host=HOST, port=PORT)
608