def test_infinite_loop(self, form: Form): def callback(elem, page_index, elem_index): if page_index == 0 and elem_index == 0: return 'First' return Value.EMPTY with pytest.raises(InfiniteLoop): form.fill(callback, fill_optional=False)
def form_with_dump(url, session=None): form_data = [] form = Form() orig_parse = form._parse def dump(data): # replace video url data = rewrite_links(data) # erase the form url data[Form._DocIndex.URL] = '0' * len(data[Form._DocIndex.URL]) nonlocal form_data form_data = data return orig_parse(data) form._parse = dump form.load(url, session=session) return form, form_data
def form(): """ A form with 3 pages, each has 2 dropdowns. Each dropdown has three options: - "Go to the first page" - "Go to the second page" - "Go to submit page" """ pages = [Page.first()] + [ TestTransitions._page(100000 + 1000 * i) for i in range(2) ] for page in pages: for i in range(2): options = [ ActionOption(value=f'First', other=False, action=_Action.FIRST), ActionOption(value=f'Second', other=False, action=pages[1].id), ActionOption(value=f'Submit', other=False, action=_Action.SUBMIT), ] page.append( TestTransitions._dropdown( id_=page.id + 100 * i, # just unique ids entry_id=page.id + 100 * i + 10, options=options)) form = Form() form.pages = pages form._resolve_actions() form.is_loaded = True return form
def test_submit_not_loaded(self): form = Form() with pytest.raises(FormNotLoaded): form.submit()
def test_fill_not_loaded(self): form = Form() with pytest.raises(FormNotLoaded): form.fill()
def main(): ua = FakeUserAgent() # A session for form loading and submission sess = requests.session() sess.headers['User-Agent'] = ua.chrome # Mean time between submissions mean_dt = 60 parser = argparse.ArgumentParser() parser.add_argument( 'url', help='The form url (https://docs.google.com/forms/d/e/.../viewform)') args = parser.parse_args() form = Form() form.load(args.url, session=sess) filler = Filler() # Show the form print(form.to_str(2)) # Use filler to cache custom callback values, if needed (will be reused later) form.fill(filler.callback, fill_optional=True) # Show the form with answers print(form.to_str(2, include_answer=True)) print() for i in range(10): last = time_now() print(f'[{asctime()}] Submit {i+1}... ', end='') sep = '' filled = False for _ in range(10): # Retry if InfiniteLoop is raised try: form.fill(filler.callback, fill_optional=True) filled = True break except InfiniteLoop: sep = ' ' print('X', end='') sleep(0.1) except ValidationError as err: # Most probably the default callback failed on an element with a validator. print(f'{sep}Failed: {err}') sleep(1) break if not filled: continue try: form.submit(session=sess) # You may want to use history emulation: # submission is faster, but it is still experimental # form.submit(session=sess, emulate_history=True) print(sep + 'OK', end='') except ClosedForm: print(sep + 'Form is closed') break except RuntimeError: # Incorrect response code or page prediction failed print(sep + 'Failed', end='') # Poisson distribution for (submissions / timeframe) delta = random.expovariate(1 / mean_dt) print(f', sleeping for {round(delta)}s') sleep(max(0.0, last + delta - time_now()))
def load_dump(form_type): url = getattr(fake_urls.FormUrl, form_type) form = Form() form.load(url, session=fake_session) return form
def load_form(url): form = Form() form.load(url, session=session) return form