Completed
Push — master ( 66e86e...96649a )
by Chris
43s
created

numbergroup()   A

Complexity

Conditions 1

Size

Total Lines 75

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 75
rs 9
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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('/numbergroup')
81
def numbergroup():
82
    """Fake endpoint."""
83
    dataset = int(request.args.get('dataset', 0))
84
    # multiple examples shown here for variadic demonstrations
85
    datas = [
86
        [
87
            {
88
                "title": "Number of widgets sold in last day",
89
                "description": 'This is a good sign',
90
                "data": 32515.0,
91
                "color": "green",
92
            },
93
            {
94
                "title": "New customers signed up this week",
95
                "description": 'New user accounts created',
96
                "data": 740,
97
            },
98
            {
99
                "title": "Average Daily Uses",
100
                "description": "(aka DAU)",
101
                "data": 541200,
102
                "noformat": False,
103
            },
104
            {
105
                "title": "Max concurrent users this week",
106
                "description": "Server load peak",
107
                "data": 123401,
108
                "color": "orange",
109
                "noformat": True,
110
            },
111
        ],
112
        [
113
            {
114
                "title": "Simple thing",
115
                "data": 123,
116
                "width": "33%",
117
                "description": "Just a simple number"
118
            },
119
            {
120
                "title": "Simple thing 2",
121
                "data": 4033,
122
                "width": "33%",
123
                "description": "Just a simple number"
124
            },
125
            {
126
                "title": "Simple thing 3",
127
                "data": 49102,
128
                "width": "33%",
129
                "description": "Just a simple number"
130
            },
131
        ],
132
        [
133
            {
134
                "title": "Average time on site",
135
                "description": "Signed in to signed out (units nostyle)",
136
                "data": '20 minutes',
137
                "color": "#7D4EE4",
138
            },
139
            {
140
                "title": "Average time on site page X",
141
                "description": "Signed in to signed out (custom units style)",
142
                "data": 15,
143
                "units": "minutes",
144
            },
145
            {
146
                "title": "Average $ spent per day",
147
                "description": "Yeeehaw (custom units style)",
148
                "data": 130,
149
                "units": "dollars"
150
            },
151
        ]
152
    ]
153
    return jsonify(datas[dataset])
154
155
156
@cross_origin()
157
@app.route('/combination')
158
def combination():
159
    """Fake endpoint."""
160
    data = {
161
        'columns': [
162
            ['data1', 30, 20, 50, 40, 60, 50],
163
            ['data2', 200, 130, 90, 240, 130, 220],
164
            ['data3', 300, 200, 160, 400, 250, 250],
165
            ['data4', 200, 130, 90, 240, 130, 220],
166
            ['data5', 130, 120, 150, 140, 160, 150],
167
            ['data6', 90, 70, 20, 50, 60, 120],
168
        ],
169
        'type': 'bar',
170
        'types': {
171
            'data3': 'spline',
172
            'data4': 'line',
173
            'data6': 'area',
174
        },
175
        'groups': [
176
            ['data1', 'data2'],
177
        ]
178
    }
179
    return jsonify(dict(data=data))
180
181
182
@cross_origin()
183
@app.route('/timeseriesc3')
184
def timeseriesc3():
185
    """Fake endpoint."""
186
    return jsonify(dict(
187
        dates=[
188
            '19{}-{}-{}'.format(rr(10, 99), rr(10, 31), rr(10, 31))
189
            for _ in range(4)
190
        ],
191
        abc=rr_list(max_range=4),
192
        cde=rr_list(max_range=4),
193
    ))
194
195
196
@cross_origin()
197
@app.route('/stacked-bar')
198
def stackedbar():
199
    """Fake endpoint."""
200
    return jsonify({
201
        'data': {
202
            'columns': [
203
                ['data1', -30, 200, 200, 400, -150, 250],
204
                ['data2', 130, 100, -100, 200, -150, 50],
205
                ['data3', -230, 200, 200, -300, 250, 250]
206
            ],
207
            'type': 'bar',
208
            'groups': [
209
                ['data1', 'data2']
210
            ]
211
        },
212
        'grid': {
213
            'y': {
214
                'lines': [{'value': 0}]
215
            }
216
        }
217
    })
218
219
220
@cross_origin()
221
@app.route('/wordcloud')
222
def wordcloud():
223
    """Fake endpoint."""
224
    words = [
225
        'awesome', 'rad', 'neato', 'the', 'flask', 'jsondash', 'graphs',
226
        'charts', 'd3', 'js', 'dashboards', 'c3',
227
    ]
228
    sizes = range(len(words))
229
    data = [
230
        {
231
            'text': word,
232
            'size': sizes[i] * 12
233
        }
234
        for i, word in enumerate(words)
235
    ]
236
    return jsonify(data)
237
238
239
@cross_origin()
240
@app.route('/sigma')
241
def sigma():
242
    """Fake endpoint."""
243
    chart_name = request.args.get('name', 'basic')
244
    if chart_name == 'random':
245
        nodes = request.args.get('nodes', 'abcdefghij')
246
        _vertices = list(nodes)
247
        _edges = combinations(_vertices, 2)
248
        edges, vertices = [], []
249
        for (frm, to) in _edges:
250
            edges.append(dict(
251
                id='{}-{}'.format(frm, to),
252
                color=rand_hex_color(),
253
                source=frm,
254
                target=to,
255
                size=rr(1, 10),
256
                x=rr(1, 100),
257
                y=rr(1, 100),
258
            ))
259
        for vertex in _vertices:
260
            vertices.append(dict(
261
                id=vertex,
262
                size=rr(1, 10),
263
                x=rr(1, 100),
264
                y=rr(1, 100),
265
                color=rand_hex_color(),
266
                label='node {}'.format(vertex),
267
            ))
268
        data = dict(
269
            nodes=vertices,
270
            edges=edges,
271
        )
272
        return jsonify(data)
273
    filename = '{}/examples/sigma/{}.json'.format(cwd, chart_name)
274
    try:
275
        with open(filename, 'r') as chartjson:
276
            return chartjson.read()
277
    except IOError:
278
        pass
279
    return jsonify({})
280
281
282
@cross_origin()
283
@app.route('/cytoscape')
284
def cytoscape():
285
    """Fake endpoint.
286
287
    Reads data from a local cytoscape spec, and if there is a
288
    remote url specified, (assuming it exists here), open and load it as well.
289
290
    This returns all required json as a single endpoint.
291
    """
292
    chart_name = request.args.get('name', 'dagre')
293
    filename = '{}/examples/cytoscape/{}.json'.format(cwd, chart_name)
294
    try:
295
        with open(filename, 'r') as chartjson:
296
            return chartjson.read()
297
    except IOError:
298
        pass
299
    return jsonify({})
300
301
302
@cross_origin()
303
@app.route('/vegalite')
304
def vegalite():
305
    """Fake endpoint.
306
307
    Reads data from a local vega spec, and if there is a
308
    remote url specified, (assuming it exists here), open and load it as well.
309
310
    This returns all required json as a single endpoint.
311
    """
312
    chart_type = request.args.get('type', 'bar')
313
    filename = '{}/examples/vegalite/{}.json'.format(cwd, chart_type)
314
    try:
315
        with open(filename, 'r') as chartjson:
316
            chartjson = chartjson.read()
317
            data = json.loads(chartjson)
318
            if data.get('data', {}).get('url') is not None:
319
                datapath = '{}/examples/vegalite/{}'.format(
320
                    cwd, data['data']['url']
321
                )
322
                with open(datapath, 'r') as datafile:
323
                    if datapath.endswith('.json'):
324
                        raw_data = datafile.read()
325
                        raw_data = json.loads(raw_data)
326
                    # TODO: adding csv support for example.
327
                    data.update(data=dict(
328
                        name='some data',
329
                        values=raw_data,
330
                    ))
331
                    return jsonify(data)
332
            else:
333
                return chartjson
334
    except IOError:
335
        pass
336
    return jsonify({})
337
338
339
@cross_origin()
340
@app.route('/plotly')
341
def plotly():
342
    """Fake endpoint."""
343
    chart_type = request.args.get('chart', 'line')
344
    filename = '{}/examples/plotly/{}.json'.format(cwd, chart_type)
345
    with open(filename, 'r') as chartjson:
346
        return chartjson.read()
347
    return jsonify({})
348
349
350
@cross_origin
351
@app.route('/plotly-dynamic')
352
def plotly_dynamic():
353
    """Fake endpoint."""
354
    filename = '{}/examples/plotly/bar_line_dynamic.json'.format(cwd)
355
    with open(filename, 'r') as chartjson:
356
        return chartjson.read()
357
    return jsonify({})
358
359
360
@cross_origin()
361
@app.route('/timeline')
362
def timeline():
363
    """Fake endpoint."""
364
    with open('{}/examples/timeline3.json'.format(cwd), 'r') as timelinejson:
365
        return timelinejson.read()
366
    return jsonify({})
367
368
369
@app.route('/dtable', methods=['GET'])
370
def dtable():
371
    """Fake endpoint."""
372
    if 'stress' in request.args:
373
        return jsonify([
374
            dict(
375
                foo=rr(1, 1000),
376
                bar=rr(1, 1000),
377
                baz=rr(1, 1000),
378
                quux=rr(1, 1000)) for _ in range(STRESS_MAX_POINTS)
379
        ])
380
    fname = 'dtable-override' if 'override' in request.args else 'dtable'
381
    with open('{}/examples/{}.json'.format(os.getcwd(), fname), 'r') as djson:
382
        return djson.read()
383
    return jsonify({})
384
385
386
@cross_origin()
387
@app.route('/timeseries')
388
def timeseries():
389
    """Fake endpoint."""
390
    return jsonify({
391
        "dates": dates_list(),
392
        "line1": rr_list(max_range=10),
393
        "line2": rr_list(max_range=10),
394
        "line3": rr_list(max_range=10),
395
    })
396
397
398
@cross_origin()
399
@app.route('/custom')
400
def custompage():
401
    """Fake endpoint."""
402
    kwargs = dict(number=rr(1, 1000))
403
    return render_template('examples/custom.html', **kwargs)
404
405
406
@cross_origin()
407
@app.route('/gauge')
408
def gauge():
409
    """Fake endpoint."""
410
    return jsonify({'data': rr(1, 100)})
411
412
413
@cross_origin()
414
@app.route('/area-custom')
415
def area_custom():
416
    """Fake endpoint."""
417
    return jsonify({
418
        "data": {
419
            "columns": [
420
                ["data1", 300, 350, 300, 0, 0, 0],
421
                ["data2", 130, 100, 140, 200, 150, 50]
422
            ],
423
            "types": {
424
                "data1": "area",
425
                "data2": "area-spline"
426
            }
427
        }
428
    })
429
430
431
@cross_origin()
432
@app.route('/scatter')
433
def scatter():
434
    """Fake endpoint."""
435
    if 'override' in request.args:
436
        with open('{}/examples/overrides.json'.format(cwd), 'r') as jsonfile:
437
            return jsonfile.read()
438
    return jsonify({
439
        "bar1": [1, 2, 30, 12, 100],
440
        "bar2": rr_list(max_range=40),
441
        "bar3": rr_list(max_range=40),
442
        "bar4": [-10, 1, 5, 4, 10, 20],
443
    })
444
445
446
@cross_origin()
447
@app.route('/pie')
448
def pie():
449
    """Fake endpoint."""
450
    letters = list('abcde')
451
    if 'stress' in request.args:
452
        letters = range(STRESS_MAX_POINTS)
453
    return jsonify({'data {}'.format(name): rr(1, 100) for name in letters})
454
455
456
@cross_origin()
457
@app.route('/custom-inputs')
458
def custom_inputs():
459
    """Fake endpoint."""
460
    _range = int(request.args.get('range', 5))
461
    entries = int(request.args.get('entries', 3))
462
    starting = int(request.args.get('starting_num', 0))
463
    prefix = request.args.get('prefix', 'item')
464
    if 'override' in request.args:
465
        show_axes = request.args.get('show_axes', False)
466
        show_axes = show_axes == 'on'
467
        data = dict(
468
            data=dict(
469
                columns=[
470
                    ['{} {}'.format(prefix, i)] + rr_list(max_range=entries)
471
                    for i in range(starting, _range)
472
                ],
473
            )
474
        )
475
        if show_axes:
476
            data.update(axis=dict(
477
                x=dict(label='This is the X axis'),
478
                y=dict(label='This is the Y axis')))
479
        return jsonify(data)
480
    return jsonify({
481
        i: rr_list(max_range=_range) for i in range(starting, entries)
482
    })
483
484
485
@cross_origin()
486
@app.route('/bar')
487
def barchart():
488
    """Fake endpoint."""
489
    if 'stress' in request.args:
490
        return jsonify({
491
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
492
            for k in range(STRESS_MAX_POINTS)
493
        })
494
    return jsonify({
495
        "bar1": [1, 2, 30, 12, 100],
496
        "bar2": rr_list(max_range=5),
497
        "bar3": rr_list(max_range=5),
498
    })
499
500
501
@cross_origin()
502
@app.route('/line')
503
def linechart():
504
    """Fake endpoint."""
505
    if 'stress' in request.args:
506
        return jsonify({
507
            'bar-{}'.format(k): rr_list(max_range=STRESS_MAX_POINTS)
508
            for k in range(STRESS_MAX_POINTS)
509
        })
510
    return jsonify({
511
        "line1": [1, 4, 3, 10, 12, 14, 18, 10],
512
        "line2": [1, 2, 10, 20, 30, 6, 10, 12, 18, 2],
513
        "line3": rr_list(),
514
    })
515
516
517
@cross_origin()
518
@app.route('/shared')
519
def shared_data():
520
    """Fake endpoint to demonstrate sharing data from one source."""
521
    letters = list('abcde')
522
    piedata = {'data {}'.format(name): rr(1, 100) for name in letters}
523
    bardata = {
524
        "bar1": [1, 2, 30, 12, 100],
525
        "bar2": rr_list(max_range=5),
526
        "bar3": rr_list(max_range=5),
527
    }
528
    linedata = {
529
        "line1": [1, 4, 3, 10, 12, 14, 18, 10],
530
        "line2": [1, 2, 10, 20, 30, 6, 10, 12, 18, 2],
531
        "line3": rr_list(),
532
    }
533
    return jsonify({
534
        'multicharts': {
535
            'line': linedata,
536
            'bar': bardata,
537
            'pie': piedata,
538
        }
539
    })
540
541
542
@cross_origin()
543
@app.route('/singlenum')
544
def singlenum():
545
    """Fake endpoint."""
546
    _min, _max = 10, 10000
547
    if 'sales' in request.args:
548
        val = locale.currency(float(rr(_min, _max)), grouping=True)
549
    else:
550
        val = rr(_min, _max)
551
    if 'negative' in request.args:
552
        val = '-{}'.format(val)
553
    return jsonify(data=val)
554
555
556
@cross_origin()
557
@app.route('/deadend')
558
def test_die():
559
    """Fake endpoint that ends in a random 50x error."""
560
    # Simulate slow connection
561
    sleep = request.args.get('sleep', True)
562
    if sleep != '':
563
        sleep_for = request.args.get('sleep_for')
564
        time.sleep(int(sleep_for) if sleep_for is not None else random())
565
    err_code = request.args.get('error_code')
566
    rand_err = choice([500, 501, 502, 503, 504])
567
    abort(int(err_code) if err_code is not None else rand_err)
568
569
570
@cross_origin()
571
@app.route('/venn')
572
def test_venn():
573
    """Fake endpoint."""
574
    data = [
575
        {'sets': ['A'], 'size': rr(10, 100)},
576
        {'sets': ['B'], 'size': rr(10, 100)},
577
        {'sets': ['C'], 'size': rr(10, 100)},
578
        {'sets': ['A', 'B'], 'size': rr(10, 100)},
579
        {'sets': ['A', 'B', 'C'], 'size': rr(10, 100)},
580
    ]
581
    return jsonify(data)
582
583
584
@cross_origin()
585
@app.route('/sparklines', methods=['GET'])
586
def sparklines():
587
    """Fake endpoint."""
588
    if any([
589
        'pie' in request.args,
590
        'discrete' in request.args,
591
    ]):
592
        return jsonify([rr(1, 100) for _ in range(10)])
593
    return jsonify([[i, rr(i, 100)] for i in range(10)])
594
595
596
@cross_origin()
597
@app.route('/circlepack', methods=['GET'])
598
def circlepack():
599
    """Fake endpoint."""
600
    if 'stress' in request.args:
601
        # Build a very large dataset
602
        return jsonify(recursive_d3_data())
603
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
604
        return djson.read()
605
    return jsonify({})
606
607
608
@cross_origin()
609
@app.route('/treemap', methods=['GET'])
610
def treemap():
611
    """Fake endpoint."""
612
    if 'stress' in request.args:
613
        # Build a very large dataset
614
        return jsonify(recursive_d3_data())
615
    with open('{}/examples/flare.json'.format(cwd), 'r') as djson:
616
        return djson.read()
617
    return jsonify({})
618
619
620
@cross_origin()
621
@app.route('/map', methods=['GET'])
622
def datamap():
623
    """Fake endpoint."""
624
    return render_template('examples/map.html')
625
626
627
@cross_origin()
628
@app.route('/dendrogram', methods=['GET'])
629
def dendro():
630
    """Fake endpoint."""
631
    if 'stress' in request.args:
632
        # Build a very large dataset
633
        return jsonify(recursive_d3_data())
634
    filename = 'flare-simple' if 'simple' in request.args else 'flare'
635
    with open('{}/examples/{}.json'.format(cwd, filename), 'r') as djson:
636
        return djson.read()
637
    return jsonify({})
638
639
640
@cross_origin()
641
@app.route('/voronoi', methods=['GET'])
642
def voronoi():
643
    """Fake endpoint."""
644
    w, h = request.args.get('width', 800), request.args.get('height', 800)
645
    max_points = int(request.args.get('points', 100))
646
    if 'stress' in request.args:
647
        max_points = 500
648
    return jsonify([[rr(1, h), rr(1, w)] for _ in range(max_points)])
649
650
651
@cross_origin()
652
@app.route('/digraph', methods=['GET'])
653
def graphdata():
654
    """Fake endpoint."""
655
    if 'filetree' in request.args:
656
        with open('{}/examples/filetree_digraph.dot'.format(cwd), 'r') as dot:
657
            return jsonify(dict(graph=dot.read()))
658
    if 'simple' in request.args:
659
        graphdata = """
660
        digraph {
661
            a -> b;
662
            a -> c;
663
            b -> c;
664
            b -> a;
665
            b -> b;
666
        }
667
        """
668
        return jsonify(dict(graph=graphdata))
669
    nodes = list('abcdefghijkl')
670
    node_data = '\n'.join([
671
        '{0} -> {1};'.format(choice(nodes), choice(nodes))
672
        for _ in range(10)
673
    ])
674
    graphdata = """digraph {lb} {nodes} {rb}""".format(
675
        lb='{', rb='}', nodes=node_data)
676
    return jsonify(dict(
677
        graph=graphdata,
678
    ))
679
680
681
if __name__ == '__main__':
682
    PORT = int(os.getenv('PORT', 5004))
683
    HOST = os.getenv('HOST', '0.0.0.0')
684
    app.run(debug=True, host=HOST, port=PORT)
685