def extend_mturk_hit(hit_id, assignments, duration_hours, sandbox): """Add assignments, and optionally time, to an existing MTurk HIT.""" out = Output() config = get_config() config.load() mode = "sandbox" if sandbox else "live" assignments_presented = "assignments" if assignments > 1 else "assignment" duration_presented = duration_hours or 0.0 with config.override({"mode": mode}): if not click.confirm( "\n\nYou are about to add {:.1f} hours and {} {} to {} HIT {}.\n" "Continue?".format(duration_presented, assignments, assignments_presented, mode, hit_id)): out.log("Aborting...") return service = _mturk_service_from_config(sandbox) try: hit_info = service.extend_hit(hit_id=hit_id, number=assignments, duration_hours=duration_hours) except MTurkServiceException as ex: out.error( "HIT extension failed with the following error:\n{}".format( ex), ) return out.log("Updated HIT Details") out.log(tabulate.tabulate(hit_info.items()), chevrons=False)
def apps(): out = Output() config = get_config() if not config.ready: config.load() team = config.get("heroku_team", None) command_runner = HerokuInfo(team=team) my_apps = command_runner.my_apps() my_user = command_runner.login_name() listing = [] header_map = [ {"title": "UID", "id": "dallinger_uid"}, {"title": "Started", "id": "created_at"}, {"title": "URL", "id": "web_url"}, ] headers = [h["title"] for h in header_map] for app in my_apps: app_info = [] for detail in header_map: val = "" key = detail.get("id") if key: val = app.get(key, "") app_info.append(val) listing.append(app_info) if listing: out.log( "Found {} heroku apps running for user {}".format(len(listing), my_user) ) out.log(tabulate.tabulate(listing, headers, tablefmt="psql"), chevrons=False) else: out.log("No heroku apps found for user {}".format(my_user))
def debug(verbose, bot, proxy, no_browsers=False, exp_config=None): """Run the experiment locally using docker compose.""" from dallinger.docker.deployment import DockerDebugDeployment debugger = DockerDebugDeployment(Output(), verbose, bot, proxy, exp_config, no_browsers) log(header, chevrons=False) debugger.run()
def load(app, verbose, replay, exp_config=None): """Import database state from an exported zip file and leave the server running until stopping the process with <control>-c. """ if replay: exp_config = exp_config or {} exp_config["replay"] = True log(header, chevrons=False) loader = LoaderDeployment(app, Output(), verbose, exp_config) loader.run()
def wrapper(*args, **kwargs): # pragma: no cover from dallinger.docker.tools import build_image from dallinger.command_line.docker import push import docker config = get_config() config.load() image_name = config.get("docker_image_name", None) if image_name: client = docker.from_env() try: check_output(["docker", "manifest", "inspect", image_name]) print(f"Image {image_name} found on remote registry") return f(*args, **kwargs) except CalledProcessError: # The image is not on the registry. Check if it's available locally # and push it if it is. If images.get succeeds it means the image is available locally print( f"Image {image_name} not found on remote registry. Trying to push" ) raw_result = client.images.push(image_name) # This is brittle, but it's an edge case not worth more effort if not json.loads(raw_result.split("\r\n")[-2]).get("error"): print(f"Image {image_name} pushed to remote registry") return f(*args, **kwargs) # The image is not available, neither locally nor on the remote registry print( f"Could not find image {image_name} specified in experiment config as `docker_image_name`" ) raise click.Abort _, tmp_dir = setup_experiment(Output().log, exp_config=config.as_dict(), local_checks=False) build_image(tmp_dir, config.get("docker_image_base_name"), out=Output()) pushed_image = push.callback(use_existing=True) add_image_name(LOCAL_CONFIG, pushed_image) return f(*args, **kwargs)
def hits(app, sandbox): """List all HITs for the user's configured MTurk request account, or for a specific experiment id. """ if app is not None: verify_id(None, "--app", app) formatted_hit_list = [] dateformat = "%Y/%-m/%-d %I:%M:%S %p" for h in _current_hits(_mturk_service_from_config(sandbox), app): title = h["title"][:40] + "..." if len(h["title"]) > 40 else h["title"] description = ( h["description"][:60] + "..." if len(h["description"]) > 60 else h["description"] ) formatted_hit_list.append( [ h["id"], title, h["annotation"], h["status"], h["created"].strftime(dateformat), h["expiration"].strftime(dateformat), description, ] ) out = Output() out.log("Found {} hit[s]:".format(len(formatted_hit_list))) out.log( tabulate.tabulate( formatted_hit_list, headers=[ "Hit ID", "Title", "Annotation (experiment ID)", "Status", "Created", "Expiration", "Description", ], ), chevrons=False, )
def _bootstrap(exp_config=None): """Creates a directory called 'develop' which will be used to host the development version of the experiment.""" bootstrapper = DevelopmentDeployment(Output(), exp_config) log(header, chevrons=False) bootstrapper.run()
def expire(hit_id, app, sandbox, exit=True): """Expire (set to "Reviewable") an MTurk HIT by specifying a HIT ID, or by specifying a Dallinger experiment ID, in which case HITs with the experiment ID in their ``annotation`` field will be expired. """ if (hit_id and app) or not (hit_id or app): raise click.BadParameter( "Must specify --hit_id or --app, but not both.") if app is not None: verify_id(None, "--app", app) service = _mturk_service_from_config(sandbox) # Assemble the list of HITs to expire if hit_id: targets = [hit_id] else: # Find HITs based on --app value targets = [ h["id"] for h in service.get_hits( hit_filter=lambda h: h.get("annotation") == app) ] success = [] failures = [] for hit_id in targets: try: service.expire_hit(hit_id=hit_id) success.append(hit_id) except MTurkServiceException: failures.append(hit_id) out = Output() if success: out.log("Expired {} hit[s] (which may have already been expired): {}". format(len(success), ", ".join(success))) if failures: out.log("Could not expire {} hit[s]: {}".format( len(failures), ", ".join(failures))) if not success and not failures: out.error("Failed to find any matching HITs on MTurk.") if not sandbox: out.log( "If this experiment was run in the MTurk sandbox, use:\n" " `dallinger expire --sandbox --app {}`".format(app), chevrons=False, ) out.log("You can run `dallinger hits` to help troubleshoot.", chevrons=False) if exit and not success: sys.exit(1)
def compensate(recruiter, worker_id, email, dollars, sandbox): """Credit a specific worker by ID through their recruiter""" out = Output() config = get_config() config.load() mode = "sandbox" if sandbox else "live" do_notify = email is not None no_email_str = "" if email else " NOT" with config.override({"mode": mode}): rec = by_name(recruiter) if not click.confirm( '\n\nYou are about to pay worker "{}" ${:.2f} in "{}" mode using the "{}" recruiter.\n' "The worker will{} be notified by email. " "Continue?".format(worker_id, dollars, mode, recruiter, no_email_str)): out.log("Aborting...") return try: result = rec.compensate_worker(worker_id=worker_id, email=email, dollars=dollars, notify=do_notify) except Exception as ex: out.error( "Compensation failed. The recruiter reports the following error:\n{}" .format(ex), ) return out.log("HIT Details") out.log(tabulate.tabulate(result["hit"].items()), chevrons=False) out.log("Qualification Details") out.log(tabulate.tabulate(result["qualification"].items()), chevrons=False) out.log("Worker Notification") out.log(tabulate.tabulate(result["email"].items()), chevrons=False)
def email_test(): """Test email configuration and send a test email.""" out = Output() config = get_config() config.load() settings = EmailConfig(config) out.log("Email Config") out.log(tabulate.tabulate(settings.as_dict().items()), chevrons=False) problems = settings.validate() if problems: out.error( "✗ There are mail configuration problems. Fix these first:\n{}". format(problems)) return else: out.log("✓ email config looks good!") mailer = SMTPMailer( config.get("smtp_host"), config.get("smtp_username"), config.get("smtp_password"), ) msg = { "subject": "Test message from Dallinger", "sender": config.get("dallinger_email_address"), "recipients": [config.get("contact_email_on_error")], "body": "This has been a test...", } out.log( "Sending a test email from {sender} to {recipients[0]}".format(**msg)) try: mailer.send(**msg) except MessengerError: out.error("✗ Message sending failed...") raise else: out.log("✓ Test email sent successfully to {}!".format( msg["recipients"][0]))
def debug(verbose, bot, proxy, no_browsers=False, exp_config=None): """Run the experiment locally.""" debugger = DebugDeployment(Output(), verbose, bot, proxy, exp_config, no_browsers) log(header, chevrons=False) debugger.run()