def run_suite (suite): # We use a random username so that if a test fails, we don't have to do a cleaning of the DB so that the test suite can run again # This also allows us to run concurrent tests without having username conflicts. username = '******' + str (random.randint (10000, 100000)) tests = suite (username) state = {'headers': {}} t0 = timems () if not type_check (tests, 'list'): return print ('Invalid test suite, must be a list.') counter = 1 def run_test (test, counter): result = request (state, test, counter, username) for test in tests: # If test is nested, run a nested loop if not (type_check (test[0], 'str')): for subtest in test: run_test (subtest, counter) counter += 1 else: run_test (test, counter) counter += 1 if isinstance (threading.current_thread (), threading._MainThread): print ('Test suite successful! (' + str (timems () - t0) + 'ms)') else: return timems () - t0
def retrieveProgramsBefore (state, response, username): if not type_check (response ['body'], 'dict'): raise Exception ('Invalid response body') if not 'programs' in response ['body'] or not type_check (response ['body'] ['programs'], 'list'): raise Exception ('Invalid programs list') if len (response ['body'] ['programs']) != 0: raise Exception ('Programs list should be empty')
def request (state, test, counter, username): start = timems () if isinstance (threading.current_thread (), threading._MainThread): print ('Start #' + str (counter) + ': ' + test [0]) # If no explicit cookie passed, use the one from the state if not 'cookie' in test [3] and 'cookie' in state ['headers']: test [3] ['cookie'] = state ['headers'] ['cookie'] # If path, headers or body are functions, invoke them passing them the current state if type_check (test[2], 'fun'): test[2] = test[2] (state) if type_check (test[3], 'fun'): test[3] = test[3] (state) if type_check (test[4], 'fun'): test[4] = test[4] (state) if type_check (test[4], 'dict'): test[3] ['content-type'] = 'application/json' test[4] = json.dumps (test [4]) # We pass the X-Testing header to let the server know that this is a request coming from an E2E test, thus no transactional emails should be sent. test [3] ['X-Testing'] = '1' r = getattr (requests, test [1]) (host + test [2], headers=test[3], data=test[4]) if 'Content-Type' in r.headers and r.headers ['Content-Type'] == 'application/json': body = r.json () else: body = r.text if r.history and r.history [0]: # This will be the case if there's a redirect code = r.history [0].status_code else: code = r.status_code output = { 'code': code, 'headers': r.headers, 'body': body } if (code != test[5]): print (output) raise Exception ('A test failed!') if len (test) == 7: test [6] (state, output, username) if isinstance (threading.current_thread (), threading._MainThread): print ('Done #' + str (counter) + ': ' + test [0] + ' - ' + str (r.status_code) + ' (' + str (timems () - start) + 'ms)') return output
def request(test, counter): start = timems() print('Start #' + str(counter) + ': ' + test[0]) # If no explicit cookie passed, use the one from the state if not 'cookie' in test[3] and 'cookie' in state['headers']: test[3]['cookie'] = state['headers']['cookie'] # If path, headers or body are functions, invoke them passing them the current state if type_check(test[2], 'fun'): test[2] = test[2](state) if type_check(test[3], 'fun'): test[3] = test[3](state) if type_check(test[4], 'fun'): test[4] = test[4](state) if type_check(test[4], 'dict'): test[3]['content-type'] = 'application/json' test[4] = json.dumps(test[4]) r = getattr(requests, test[1])(host + test[2], headers=test[3], data=test[4]) if 'Content-Type' in r.headers and r.headers[ 'Content-Type'] == 'application/json': body = r.json() else: body = r.text if r.history and r.history[0]: # This will be the case if there's a redirect code = r.history[0].status_code else: code = r.status_code output = {'code': code, 'headers': r.headers, 'body': body} if (code != test[5]): print(output) raise Exception('A test failed!') if len(test) == 7: test[6](state, output) print('Done #' + str(counter) + ': ' + test[0] + ' - ' + str(r.status_code) + ' (' + str(timems() - start) + 'ms)') return output
def var_homogeneity(x1, x2, alpha=0.1, verbose=1): x1 = utils.type_check(x1) x2 = utils.type_check(x2) _F, _p = base.var_homo_test(x1, x2) if verbose == 1: print("使用F-test检验方差齐性:") print("p = {0}, alpha = {1}".format(_p, alpha)) if _p < alpha: print("p < alpha, 差异有统计学意义,两组总体方差不等") else: print("p >= alpha, 差异无统计学意义,尚不能认定两组总体方差不等") return _F, _p
def retrieveProgramsAfter (state, response, username): if not type_check (response ['body'], 'dict'): raise Exception ('Invalid response body') if not 'programs' in response ['body'] or not type_check (response ['body'] ['programs'], 'list'): raise Exception ('Invalid programs list') if len (response ['body'] ['programs']) != 1: raise Exception ('Programs list should contain one program') program = response ['body'] ['programs'] [0] state ['program'] = program if not type_check (program, 'dict'): raise Exception ('Invalid program type') if not 'code' in program or program ['code'] != 'print Hello world': raise Exception ('Invalid program.code') if not 'level' in program or program ['level'] != 1: raise Exception ('Invalid program.level')
def recover(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 # If username has an @-sign, then it's an email if re.match('@', body['username']): username = r.hget('emails', body['username']) if not username: return 'invalid username/password', 403 else: username = body['username'] username = username.strip().lower() user = r.hgetall('user:'******'invalid username', 403 token = make_salt() hashed = hash(token, make_salt()) r.setex('token:' + hashed, session_length, body['username']) # TODO: when in non-local environment, email the token instead of returning it return token
def update_profile(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if 'email' in body: if not object_check(body, 'email', 'str'): return 'body.email must be a string', 400 if not re.match( '^(([a-zA-Z0-9_\.\-]+)@([\da-zA-Z\.\-]+)\.([a-zA-Z\.]{2,6})\s*)$', body['email']): return 'body.email must be a valid email', 400 if 'country' in body: if not body['country'] in countries: return 'body.country must be a valid country', 400 if 'age' in body: if not object_check(body, 'age', 'int') or body['age'] <= 0: return 'body.age must be an integer larger than 0', 400 if 'gender' in body: if body['gender'] != 'm' and body['gender'] != 'f': return 'body.gender must be m/f', 400 if 'email' in body: r.hdel('emails', user['email']) r.hset('emails', body['email'], user['username']) r.hset('user:'******'username'], 'email', body['email']) if 'country' in body: r.hset('user:'******'username'], 'country', body['country']) if 'age' in body: r.hset('user:'******'username'], 'age', body['age']) if 'gender' in body: r.hset('user:'******'username'], 'gender', body['gender']) return '', 200
def recover (): body = request.json # Validations if not type_check (body, 'dict'): return 'body must be an object', 400 if not object_check (body, 'username', 'str'): return 'body.username must be a string', 400 # If username has an @-sign, then it's an email if '@' in body ['username']: user = db_get ('users', {'email': body ['username'].strip ().lower ()}, True) else: user = db_get ('users', {'username': body ['username'].strip ().lower ()}) if not user: return 'invalid username', 403 token = make_salt () hashed = hash (token, make_salt ()) db_set ('tokens', {'id': user ['username'], 'token': hashed, 'ttl': times () + session_length}) if not env: # If on local environment, we return email verification token directly instead of emailing it, for test purposes. return jsonify ({'username': user ['username'], 'token': token}), 200 else: send_email_template ('recover_password', user ['email'], requested_lang (), os.getenv ('BASE_URL') + '/reset?username='******'username']) + '&token=' + urllib.parse.quote_plus (token)) return '', 200
def login(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'username must be a string', 400 if not object_check(body, 'password', 'str'): return 'password must be a string', 400 # If username has an @-sign, then it's an email if re.match('@', body['username']): username = r.hget('emails', body['username']) if not username: return 'invalid username/password', 403 else: username = body['username'] username = username.strip().lower() user = r.hgetall('user:'******'invalid username/password', 403 if not check_password(body['password'], user['password']): return 'invalid username/password', 403 cookie = make_salt() r.setex('sess:' + cookie, session_length, body['username']) r.hset('user:'******'username'], 'lastAccess', timems()) resp = make_response({}) resp.set_cookie(cookie_name, value=cookie, httponly=True, path='/') return resp
def index(level, step): session_id() # Run this for the side effect of generating a session ID g.level = level = int(level) g.lang = requested_lang() g.prefix = '/hedy' # If step is a string that has more than two characters, it must be an id of a program if step and type_check(step, 'str') and len(step) > 2: result = db_get('programs', {'id': step}) if not result: return 'No such program', 404 # Allow only the owner of the program, the admin user and the teacher users to access the program user = current_user(request) if user['username'] != result['username'] and not is_admin( request) and not is_teacher(request): return 'No such program!', 404 loaded_program = result['code'] # We default to step 1 to provide a meaningful default assignment step = 1 else: loaded_program = None return hedyweb.render_assignment_editor(request=request, course=HEDY_COURSE[g.lang], level_number=level, assignment_number=step, menu=render_main_menu('hedy'), translations=TRANSLATIONS, version=version(), loaded_program=loaded_program)
def reset(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 if not object_check(body, 'token', 'str'): return 'body.token must be a string', 400 if not object_check(body, 'password', 'str'): return 'body.password be a string', 400 if len(body['password']) < 6: return 'password must be at least six characters long', 400 # There's no need to trim or lowercase username, because it should come within a link prepared by the app itself and not inputted manually by the user. token = db_get('tokens', {'id': body['username']}) if not token: return 'invalid username/token', 403 if not check_password(body['token'], token['token']): return 'invalid username/token', 403 hashed = hash(body['password'], make_salt()) token = db_del('tokens', {'id': body['username']}) db_set('users', {'username': body['username'], 'password': hashed}) user = db_get('users', {'username': body['username']}) if env: send_email_template('reset_password', user['email'], requested_lang(), None) return '', 200
def login (): body = request.json # Validations if not type_check (body, 'dict'): return 'body must be an object', 400 if not object_check (body, 'username', 'str'): return 'username must be a string', 400 if not object_check (body, 'password', 'str'): return 'password must be a string', 400 # If username has an @-sign, then it's an email if '@' in body ['username']: user = db_get ('users', {'email': body ['username'].strip ().lower ()}, True) else: user = db_get ('users', {'username': body ['username'].strip ().lower ()}) if not user: return 'invalid username/password', 403 if not check_password (body ['password'], user ['password']): return 'invalid username/password', 403 cookie = make_salt () db_set ('tokens', {'id': cookie, 'username': user ['username'], 'ttl': times () + session_length}) db_set ('users', {'username': user ['username'], 'last_login': timems ()}) resp = make_response ({}) resp.set_cookie (cookie_name, value=cookie, httponly=True, path='/') return resp
def mark_as_teacher(): if not is_admin(request): return 'unauthorized', 403 body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'body.username must be a string', 400 if not object_check(body, 'is_teacher', 'bool'): return 'body.is_teacher must be boolean', 400 user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username', 400 db_set( 'users', { 'username': user['username'], 'is_teacher': 1 if body['is_teacher'] else 0 }) return '', 200
def signup(): body = request.json # Validations, mandatory fields if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'username must be a string', 400 if re.match('@', body['username']): return 'username cannot contain an @-sign', 400 if re.match(':', body['username']): return 'username cannot contain a colon', 400 if not object_check(body, 'password', 'str'): return 'password must be a string', 400 if len(body['password']) < 6: return 'password must be at least six characters long', 400 if not object_check(body, 'email', 'str'): return 'email must be a string', 400 if not re.match( '^(([a-zA-Z0-9_\.\-]+)@([\da-zA-Z\.\-]+)\.([a-zA-Z\.]{2,6})\s*)$', body['email']): return 'email must be a valid email', 400 # Validations, optional fields if 'country' in body: if not body['country'] in countries: return 'country must be a valid country', 400 if 'age' in body: if not object_check(body, 'age', 'int') or body['age'] <= 0: return 'age must be an integer larger than 0', 400 if 'gender' in body: if body['gender'] != 'm' and body['gender'] != 'f': return 'gender must be m/f', 400 user = r.hgetall('user:'******'username']) if user: return 'username exists', 403 email = r.hget('emails', body['email']) if email: return 'email exists', 403 hashed = hash(body['password'], make_salt()) user = { 'username': body['username'].strip().lower(), 'password': hashed, 'email': body['email'].strip().lower(), 'created': timems() } if 'country' in body: user['country'] = body['country'] if 'age' in body: user['age'] = body['age'] if 'gender' in body: user['gender'] = body['gender'] r.hmset('user:'******'username'], user) r.hset('emails', body['email'], body['username']) return '', 200
def save_program(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'code', 'str'): return 'code must be a string', 400 if not object_check(body, 'name', 'str'): return 'name must be a string', 400 if not object_check(body, 'level', 'int'): return 'level must be an integer', 400 # We execute the saved program to see if it would generate an error or not error = None try: hedy_errors = TRANSLATIONS.get_translations(requested_lang(), 'HedyErrorMessages') result = hedy.transpile(body['code'], body['level']) except hedy.HedyException as E: error_template = hedy_errors[E.error_code] error = error_template.format(**E.arguments) except Exception as E: error = str(E) name = body['name'] # We check if a program with a name `xyz` exists in the database for the username. If it does, we exist whether `xyz (1)` exists, until we find a program `xyz (NN)` that doesn't exist yet. # It'd be ideal to search by username & program name, but since DynamoDB doesn't allow searching for two indexes at the same time, this would require to create a special index to that effect, which is cumbersome. # For now, we bring all existing programs for the user and then search within them for repeated names. existing = db_get_many('programs', {'username': user['username']}, True) name_counter = 0 for program in existing: if re.match('^' + re.escape(name) + '( \(\d+\))*', program['name']): name_counter = name_counter + 1 if name_counter: name = name + ' (' + str(name_counter) + ')' db_set( 'programs', { 'id': uuid.uuid4().hex, 'session': session_id(), 'date': timems(), 'lang': requested_lang(), 'version': version(), 'level': body['level'], 'code': body['code'], 'name': name, 'server_error': error, 'username': user['username'] }) program_count = 0 if 'program_count' in user: program_count = user['program_count'] db_set('users', { 'username': user['username'], 'program_count': program_count + 1 }) return jsonify({})
def chi2_test(xtab, alpha=0.05, verbose=1): xtab = utils.type_check(xtab) _chi2, _df, _p = base.chi2_rxc(xtab) if verbose == 1: utils.compare1(_p, alpha) return _chi2, _df, _p
def login(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'username', 'str'): return 'username must be a string', 400 if not object_check(body, 'password', 'str'): return 'password must be a string', 400 # If username has an @-sign, then it's an email if '@' in body['username']: user = db_get('users', {'email': body['username'].strip().lower()}, True) else: user = db_get('users', {'username': body['username'].strip().lower()}) if not user: return 'invalid username/password', 403 if not check_password(body['password'], user['password']): return 'invalid username/password', 403 # If the number of bcrypt rounds has changed, create a new hash. new_hash = None if config['bcrypt_rounds'] != extract_bcrypt_rounds(user['password']): new_hash = hash(body['password'], make_salt()) cookie = make_salt() db_set( 'tokens', { 'id': cookie, 'username': user['username'], 'ttl': times() + session_length }) if new_hash: db_set( 'users', { 'username': user['username'], 'password': new_hash, 'last_login': timems() }) else: db_set('users', { 'username': user['username'], 'last_login': timems() }) resp = make_response({}) # We set the cookie to expire in a year, just so that the browser won't invalidate it if the same cookie gets renewed by constant use. # The server will decide whether the cookie expires. resp.set_cookie(cookie_name, value=cookie, httponly=True, secure=True, samesite='Lax', path='/', max_age=365 * 24 * 60 * 60) return resp
def render_assignment_editor(request, course, level_number, assignment_number, menu, translations, version, loaded_program, loaded_program_name, adventure_assignments, adventure_name): sublevel = None if type_check(level_number, 'str') and re.match('\d+-\d+', level_number): sublevel = int(level_number[level_number.index('-') + 1]) level_number = int(level_number[0:level_number.index('-')]) assignment = course.get_assignment(level_number, assignment_number, sublevel) if not assignment: abort(404) arguments_dict = {} # Meta stuff arguments_dict['course'] = course arguments_dict['level_nr'] = str(level_number) arguments_dict['sublevel'] = str(sublevel) if (sublevel) else None arguments_dict[ 'assignment_nr'] = assignment.step # Give this a chance to be 'None' arguments_dict['lang'] = course.language arguments_dict['level'] = assignment.level arguments_dict['prev_level'] = int(level_number) - 1 if int( level_number) > 1 else None arguments_dict['next_level'] = int(level_number) + 1 if int( level_number) < course.max_level() else None arguments_dict['next_assignment'] = int(assignment_number) + 1 if int( assignment_number) < course.max_step(level_number) else None arguments_dict['menu'] = menu arguments_dict['latest'] = version arguments_dict['selected_page'] = 'code' arguments_dict['page_title'] = f'Level {level_number} – Hedy' arguments_dict['docs'] = [attr.asdict(d) for d in assignment.docs] arguments_dict['auth'] = translations.data[course.language]['Auth'] arguments_dict['username'] = current_user(request)['username'] arguments_dict['loaded_program'] = loaded_program arguments_dict['loaded_program_name'] = loaded_program_name arguments_dict['adventure_assignments'] = adventure_assignments arguments_dict['adventure_name'] = adventure_name # Translations arguments_dict.update( **translations.get_translations(course.language, 'ui')) # Actual assignment arguments_dict.update(**attr.asdict(assignment)) # Add markdowns to docs for doc in arguments_dict['docs']: doc['markdown'] = (course.docs.get(int(level_number), doc['slug']) or { 'markdown': '' }).markdown return render_template("code-page.html", **arguments_dict)
def save_program(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'code', 'str'): return 'code must be a string', 400 if not object_check(body, 'name', 'str'): return 'name must be a string', 400 if not object_check(body, 'level', 'int'): return 'level must be an integer', 400 if 'adventure_name' in body: if not object_check(body, 'adventure_name', 'str'): return 'if present, adventure_name must be a string', 400 name = body['name'] # We check if a program with a name `xyz` exists in the database for the username. # It'd be ideal to search by username & program name, but since DynamoDB doesn't allow searching for two indexes at the same time, this would require to create a special index to that effect, which is cumbersome. # For now, we bring all existing programs for the user and then search within them for repeated names. programs = db_get_many('programs', {'username': user['username']}, True) program = {} overwrite = False for program in programs: if program['name'] == name: overwrite = True break stored_program = { 'id': program.get('id') if overwrite else uuid.uuid4().hex, 'session': session_id(), 'date': timems(), 'lang': requested_lang(), 'version': version(), 'level': body['level'], 'code': body['code'], 'name': name, 'username': user['username'] } if 'adventure_name' in body: stored_program['adventure_name'] = body['adventure_name'] if overwrite: db_update('programs', stored_program) else: db_create('programs', stored_program) program_count = 0 if 'program_count' in user: program_count = user['program_count'] db_update('users', { 'username': user['username'], 'program_count': program_count + 1 }) return jsonify({'name': name})
def run_suite(tests): if not type_check(tests, 'list'): return print('Invalid test suite, must be a list.') counter = 1 def run_test(test, counter): result = request(test, counter) for test in tests: # If test is nested, run a nested loop if not (type_check(test[0], 'str')): for subtest in test: run_test(subtest, counter) counter += 1 else: run_test(test, counter) counter += 1 print('Test suite successful! (' + str(timems() - t0) + 'ms)')
def index(level, step): # Sublevel requested if re.match ('\d+-\d+', level): pass # If level has a dash, we keep it as a string # Normal level requested elif re.match ('\d', level): try: g.level = level = int(level) except: return 'No such Hedy level!', 404 else: return 'No such Hedy level!', 404 g.lang = requested_lang() g.prefix = '/hedy' initialize_gfi_session(g.lang) loaded_program = '' loaded_program_name = '' adventure_name = '' # If step is a string that has more than two characters, it must be an id of a program if step and type_check (step, 'str') and len (step) > 2: result = db_get ('programs', {'id': step}) if not result: return 'No such program', 404 # If the program is not public, allow only the owner of the program, the admin user and the teacher users to access the program user = current_user (request) public_program = 'public' in result and result ['public'] if not public_program and user ['username'] != result ['username'] and not is_admin (request) and not is_teacher (request): return 'No such program!', 404 loaded_program = result ['code'] loaded_program_name = result ['name'] if 'adventure_name' in result: adventure_name = result ['adventure_name'] # We default to step 1 to provide a meaningful default assignment step = 1 adventure_assignments = load_adventure_assignments_per_level(g.lang, level) return hedyweb.render_assignment_editor( request=request, course=HEDY_COURSE[g.lang], level_number=level, assignment_number=step, menu=render_main_menu('hedy'), translations=TRANSLATIONS, version=version(), adventure_assignments=adventure_assignments, loaded_program=loaded_program, loaded_program_name=loaded_program_name, adventure_name=adventure_name)
def adventure_page(adventure_name, level): user = current_user (request) level = int (level) adventures = load_adventure_for_language (requested_lang ()) # If requested adventure does not exist, return 404 if not adventure_name in adventures ['adventures']: return 'No such Hedy adventure!', 404 adventure = adventures ['adventures'] [adventure_name] # If no level is specified (this will happen if the last element of the path (minus the query parameter) is the same as the adventure_name) if re.sub (r'\?.+', '', request.url.split ('/') [len (request.url.split ('/')) - 1]) == adventure_name: # If user is logged in, check if they have a program for this adventure # If there are many, note the highest level for which there is a saved program desired_level = 0 if user ['username']: existing_programs = db_get_many ('programs', {'username': user ['username']}, True) for program in existing_programs: if 'adventure_name' in program and program ['adventure_name'] == adventure_name and program ['level'] > desired_level: desired_level = program ['level'] # If the user has a saved program for this adventure, redirect them to the level with the highest adventure if desired_level != 0: return redirect(request.url.replace ('/' + adventure_name, '/' + adventure_name + '/' + str (desired_level)), code=302) # If user is not logged in, or has no saved programs for this adventure, default to the lowest level available for the adventure if desired_level == 0: for key in adventure ['levels'].keys (): if type_check (key, 'int') and (desired_level == 0 or desired_level > key): desired_level = key level = desired_level # If requested level is not in adventure, return 404 if not level in adventure ['levels']: abort(404) initialize_gfi_session(requested_lang()) adventure_assignments = load_adventure_assignments_per_level(requested_lang(), level) g.prefix = '/hedy' return hedyweb.render_assignment_editor( request=request, course=HEDY_COURSE[requested_lang()], level_number=level, assignment_number=1, menu=render_main_menu('hedy'), translations=TRANSLATIONS, version=version(), adventure_assignments=adventure_assignments, # The relevant loaded program will be available to client-side js and it will be loaded by js. loaded_program='', loaded_program_name='', adventure_name=adventure_name)
def normality_test(x, alpha=0.1, verbose=1): x = utils.type_check(x) p_skew, p_kurtosis = base.norm_moment(x) if verbose == 1: print("使用矩法(动差法)检验正态性:") print("p_skew = {0}, p_kurtosis = {1}, alpha = {2}".format( p_skew, p_kurtosis, alpha)) if p_skew < alpha and p_kurtosis < alpha: print("p_skew < alpha, p_kurtosis < alpha, 这些样本不服从正态分布") else: print("尚不能内定这些样本不服从正态分布") return p_skew, p_kurtosis
def share_unshare_program(user): body = request.json if not type_check (body, 'dict'): return 'body must be an object', 400 if not object_check (body, 'id', 'str'): return 'id must be a string', 400 if not object_check (body, 'public', 'bool'): return 'public must be a string', 400 result = db_get ('programs', {'id': body ['id']}) if not result or result ['username'] != user ['username']: return 'No such program!', 404 db_update ('programs', {'id': body ['id'], 'public': 1 if body ['public'] else None}) return jsonify({})
def chi2_paired(xtab, alpha=0.05, verbose=1): xtab = utils.type_check(xtab) if xtab.shape != (2, 2): raise IOError("配对卡方检验仅支持四格表资料!!!") b, c = xtab[0, 1], xtab[1, 0] b_c = b + c if b_c >= 40: _chi2 = (b - c)**2 / b_c else: _chi2 = (np.abs(b - c) - 1)**2 / b_c _p = stats.chi2.sf(_chi2, 1) if verbose == 1: utils.compare0(_p, alpha) return _chi2, 1, _p
def change_password(user): body = request.json if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'oldPassword', 'str'): return 'body.oldPassword must be a string', 400 if not object_check(body, 'newPassword', 'str'): return 'body.newPassword must be a string', 400 if not check_password(body['oldPassword'], user['password']): return 'invalid username/password', 403 hashed = hash(body['newPassword'], make_salt()) r.hset('user:'******'username'], 'password', hashed) return '', 200
def qqplot(x): x = utils.type_check(x) sigma = utils.sample_std(x) x.sort() qi = (x - x.mean()) / sigma i = np.arange(x.size) + 1 ti = (i - 0.5) / x.size pi = -norm.isf(ti) line = [-4, 4] plt.figure() plt.scatter(pi, qi, s=25, marker='o') plt.plot(line, line, lw=0.5, c='black') plt.xlabel("t Quantiles") plt.ylabel("Studentized Residuals") plt.title("Q-Q Plot") plt.show()
def reset(): body = request.json # Validations if not type_check(body, 'dict'): return 'body must be an object', 400 if not object_check(body, 'token', 'str'): return 'body.token must be a string', 400 if not object_check(body, 'password', 'str'): return 'body.password be a string', 400 username = r.get('token:' + body['token']) if not username: return 'invalid token', 403 hashed = hash(body['password'], make_salt()) r.delete('token:' + body['token']) r['hset']('user:'******'password', hashed) return {}, 200
def update_profile (user): body = request.json if not type_check (body, 'dict'): return 'body must be an object', 400 if 'email' in body: if not object_check (body, 'email', 'str'): return 'body.email must be a string', 400 if not re.match ('^(([a-zA-Z0-9_\.\-]+)@([\da-zA-Z\.\-]+)\.([a-zA-Z\.]{2,6})\s*)$', body ['email']): return 'body.email must be a valid email', 400 if 'country' in body: if not body ['country'] in countries: return 'body.country must be a valid country', 400 if 'birth_year' in body: if not object_check (body, 'birth_year', 'int') or body ['birth_year'] <= 1900 or body ['birth_year'] > datetime.datetime.now ().year: return 'birth_year must be a year between 1900 and ' + str (datetime.datetime.now ().year), 400 if 'gender' in body: if body ['gender'] != 'm' and body ['gender'] != 'f' and body ['gender'] != 'o': return 'body.gender must be m/f/o', 400 resp = {} if 'email' in body: email = body ['email'].strip ().lower () if email != user ['email']: exists = db_get ('users', {'email': email}, True) if exists: return 'email exists', 403 token = make_salt () hashed_token = hash (token, make_salt ()) db_set ('users', {'username': user ['username'], 'email': email, 'verification_pending': hashed_token}) if not env: # If on local environment, we return email verification token directly instead of emailing it, for test purposes. resp = {'username': user ['username'], 'token': hashed_token} else: send_email_template ('welcome_verify', email, requested_lang (), os.getenv ('BASE_URL') + '/auth/verify?username='******'&token=' + urllib.parse.quote_plus (hashed_token)) if 'country' in body: db_set ('users', {'username': user ['username'], 'country': body ['country']}) if 'birth_year' in body: db_set ('users', {'username': user ['username'], 'birth_year': body ['birth_year']}) if 'gender' in body: db_set ('users', {'username': user ['username'], 'gender': body ['gender']}) return jsonify (resp)