1
+ from collections import Counter , namedtuple
2
+ import csv
3
+ import re
4
+ from typing import List
5
+
6
+ from apistar import App , Route , types , validators
7
+ from apistar .http import JSONResponse
8
+
9
+ # helpers
10
+
11
+ DATA = './marvel-wikia-data.csv'
12
+ Character = namedtuple ('Character' , 'pid name sid align sex appearances year' )
13
+
14
+
15
+ def _load_marvel_data (data = DATA ):
16
+ '''write a function to parse marvel-wikia-data.csv, see
17
+ https://docs.python.org/3.7/library/csv.html#csv.DictReader
18
+ should return a list of OrderedDicts or a list of Character
19
+ namedtuples (see Character namedtuple above')'''
20
+ with open (data ) as csvfile :
21
+ for row in csv .DictReader (csvfile ):
22
+ name = re .sub (r'(.*?)\(.*' , r'\1' , row ['name' ]).strip ()
23
+ # could do:
24
+ # yield row
25
+ # but namedtuple is more elgant
26
+ # tried to make pytest work with both
27
+ if row ['Year' ] == '' :
28
+ row ['Year' ] = None
29
+ else :
30
+ row ['Year' ] = int (row ['Year' ])
31
+ yield Character (pid = int (row ['page_id' ]),
32
+ name = name ,
33
+ sid = row ['ID' ],
34
+ align = row ['ALIGN' ],
35
+ sex = row ['SEX' ],
36
+ appearances = row ['APPEARANCES' ],
37
+ year = row ['Year' ])
38
+
39
+
40
+ data = list (_load_marvel_data ())
41
+ characters = {character .pid : character ._asdict () for character in data }
42
+
43
+ VALID_SIDS = set ([value ['sid' ] for key , value in characters .items ()])
44
+ VALID_ALIGNS = set ([value ['align' ] for key , value in characters .items ()])
45
+ VALID_SEXES = set ([value ['sex' ] for key , value in characters .items ()])
46
+ MIN_YEAR = min ([value ['year' ] if value ['year' ] is not None else 10000 for key , value in characters .items ()])
47
+
48
+ CHARACTER_NOT_FOUND = 'This character is so secret, they don\' t exist!'
49
+
50
+ # definition
51
+
52
+ class MarvelCharacter (types .Type ):
53
+ pid = validators .Integer (allow_null = True )
54
+ name = validators .String (max_length = 100 )
55
+ sid = validators .String (enum = list (VALID_SIDS ) , default = '' )
56
+ align = validators .String (enum = list (VALID_ALIGNS ) , default = '' )
57
+ sex = validators .String (enum = list (VALID_SEXES ) , default = '' )
58
+ appearances = validators .String (default = '' )
59
+ year = validators .Integer (minimum = MIN_YEAR , allow_null = True )
60
+
61
+ # API methods
62
+
63
+ def list_characters () -> List [MarvelCharacter ]:
64
+ return [MarvelCharacter (character ) for key , character in sorted (characters .items ())]
65
+
66
+ def create_character (character : MarvelCharacter ) -> JSONResponse :
67
+ pass
68
+
69
+ def get_character (character_id : int ) -> JSONResponse :
70
+ character = characters .get (character_id )
71
+ if not character :
72
+ error = {'error' : CHARACTER_NOT_FOUND }
73
+ return JSONResponse (error , status_code = 404 )
74
+
75
+ return JSONResponse (MarvelCharacter (character ), status_code = 200 )
76
+
77
+ def update_character (character_id : int , character : MarvelCharacter ) -> JSONResponse :
78
+ pass
79
+
80
+ def delete_character (character_id : int ) -> JSONResponse :
81
+ pass
82
+
83
+ routes = [
84
+ Route ('/' , method = 'GET' , handler = list_characters ),
85
+ Route ('/' , method = 'POST' , handler = create_character ),
86
+ Route ('/{character_id}/' , method = 'GET' , handler = get_character ),
87
+ Route ('/{character_id}/' , method = 'PUT' , handler = update_character ),
88
+ Route ('/{character_id}/' , method = 'DELETE' , handler = delete_character ),
89
+ ]
90
+
91
+ app = App (routes = routes )
92
+
93
+ if __name__ == '__main__' :
94
+ app .serve ('127.0.0.1' , 5000 , debug = True )
95
+ # for key, val in characters.items():
96
+ # print(val)
0 commit comments