Permalink
Browse files

Added response_group parameter to several methods. Fixes issue 433.

  • Loading branch information...
1 parent 7f8d160 commit ccfdc9ec5c0cd1044df8085ab2d2c98d4f4618d0 Mitch Garnaat committed Aug 19, 2010
Showing with 121 additions and 75 deletions.
  1. +121 −75 boto/mturk/connection.py
View
@@ -36,18 +36,22 @@ class MTurkConnection(AWSQueryConnection):
def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
is_secure=False, port=None, proxy=None, proxy_port=None,
- proxy_user=None, proxy_pass=None, host='mechanicalturk.amazonaws.com', debug=0,
+ proxy_user=None, proxy_pass=None,
+ host='mechanicalturk.amazonaws.com', debug=0,
https_connection_factory=None):
- AWSQueryConnection.__init__(self, aws_access_key_id, aws_secret_access_key,
- is_secure, port, proxy, proxy_port, proxy_user, proxy_pass,
- host, debug, https_connection_factory)
+ AWSQueryConnection.__init__(self, aws_access_key_id,
+ aws_secret_access_key,
+ is_secure, port, proxy, proxy_port,
+ proxy_user, proxy_pass, host, debug,
+ https_connection_factory)
def get_account_balance(self):
"""
"""
params = {}
- return self._process_request('GetAccountBalance', params, [('AvailableBalance', Price),
- ('OnHoldBalance', Price)])
+ return self._process_request('GetAccountBalance', params,
+ [('AvailableBalance', Price),
+ ('OnHoldBalance', Price)])
def register_hit_type(self, title, description, reward, duration,
keywords=None, approval_delay=None, qual_req=None):
@@ -73,28 +77,31 @@ def register_hit_type(self, title, description, reward, duration,
def set_email_notification(self, hit_type, email, event_types=None):
"""
- Performs a SetHITTypeNotification operation to set email notification for a specified HIT type
+ Performs a SetHITTypeNotification operation to set email
+ notification for a specified HIT type
"""
return self._set_notification(hit_type, 'Email', email, event_types)
def set_rest_notification(self, hit_type, url, event_types=None):
"""
- Performs a SetHITTypeNotification operation to set REST notification for a specified HIT type
+ Performs a SetHITTypeNotification operation to set REST notification
+ for a specified HIT type
"""
return self._set_notification(hit_type, 'REST', url, event_types)
def _set_notification(self, hit_type, transport, destination, event_types=None):
"""
- Common SetHITTypeNotification operation to set notification for a specified HIT type
+ Common SetHITTypeNotification operation to set notification for a
+ specified HIT type
"""
assert type(hit_type) is str, "hit_type argument should be a string."
params = {'HITTypeId': hit_type}
# from the Developer Guide:
- # The 'Active' parameter is optional. If omitted, the active status of the HIT type's
- # notification specification is unchanged. All HIT types begin with their
- # notification specifications in the "inactive" status.
+ # The 'Active' parameter is optional. If omitted, the active status of
+ # the HIT type's notification specification is unchanged. All HIT types
+ # begin with their notification specifications in the "inactive" status.
notification_params = {'Destination': destination,
'Transport': transport,
'Version': boto.mturk.notification.NotificationMessage.NOTIFICATION_VERSION,
@@ -197,7 +204,8 @@ def get_reviewable_hits(self, hit_type=None, status='Reviewable',
page_size=10, page_number=1):
"""
Retrieve the HITs that have a status of Reviewable, or HITs that
- have a status of Reviewing, and that belong to the Requester calling the operation.
+ have a status of Reviewing, and that belong to the Requester
+ calling the operation.
"""
params = {'Status' : status,
'SortProperty' : sort_by,
@@ -212,39 +220,47 @@ def get_reviewable_hits(self, hit_type=None, status='Reviewable',
return self._process_request('GetReviewableHITs', params, [('HIT', HIT),])
def search_hits(self, sort_by='CreationTime', sort_direction='Ascending',
- page_size=10, page_number=1):
+ page_size=10, page_number=1, response_groups=None):
"""
Return all of a Requester's HITs, on behalf of the Requester.
- The operation returns HITs of any status, except for HITs that have been disposed
- with the DisposeHIT operation.
+ The operation returns HITs of any status, except for HITs that have been
+ disposed with the DisposeHIT operation.
Note:
- The SearchHITs operation does not accept any search parameters that filter the results.
+ The SearchHITs operation does not accept any search parameters that
+ filter the results.
"""
params = {'SortProperty' : sort_by,
'SortDirection' : sort_direction,
'PageSize' : page_size,
'PageNumber' : page_number}
+ # Handle optional response groups argument
+ if response_groups:
+ self.build_list_params(params, response_groups, 'ResponseGroup')
+
return self._process_request('SearchHITs', params, [('HIT', HIT),])
def get_assignments(self, hit_id, status=None,
sort_by='SubmitTime', sort_direction='Ascending',
- page_size=10, page_number=1):
+ page_size=10, page_number=1, response_groups=None):
"""
Retrieves completed assignments for a HIT.
Use this operation to retrieve the results for a HIT.
The returned ResultSet will have the following attributes:
NumResults
- The number of assignments on the page in the filtered results list,
- equivalent to the number of assignments being returned by this call.
+ The number of assignments on the page in the filtered results
+ list, equivalent to the number of assignments being returned
+ by this call.
A non-negative integer
PageNumber
- The number of the page in the filtered results list being returned.
+ The number of the page in the filtered results list being
+ returned.
A positive integer
TotalNumResults
- The total number of HITs in the filtered results list based on this call.
+ The total number of HITs in the filtered results list based
+ on this call.
A non-negative integer
The ResultSet will contain zero or more Assignment objects
@@ -259,7 +275,12 @@ def get_assignments(self, hit_id, status=None,
if status is not None:
params['AssignmentStatus'] = status
- return self._process_request('GetAssignmentsForHIT', params, [('Assignment', Assignment),])
+ # Handle optional response groups argument
+ if response_groups:
+ self.build_list_params(params, response_groups, 'ResponseGroup')
+
+ return self._process_request('GetAssignmentsForHIT', params,
+ [('Assignment', Assignment),])
def approve_assignment(self, assignment_id, feedback=None):
"""
@@ -277,52 +298,64 @@ def reject_assignment(self, assignment_id, feedback=None):
params['RequesterFeedback'] = feedback
return self._process_request('RejectAssignment', params)
- def get_hit(self, hit_id):
+ def get_hit(self, hit_id, response_groups=None):
"""
"""
params = {'HITId' : hit_id,}
+ # Handle optional response groups argument
+ if response_groups:
+ self.build_list_params(params, response_groups, 'ResponseGroup')
+
return self._process_request('GetHIT', params, [('HIT', HIT),])
def set_reviewing(self, hit_id, revert=None):
"""
Update a HIT with a status of Reviewable to have a status of Reviewing,
or reverts a Reviewing HIT back to the Reviewable status.
- Only HITs with a status of Reviewable can be updated with a status of Reviewing.
- Similarly, only Reviewing HITs can be reverted back to a status of Reviewable.
+ Only HITs with a status of Reviewable can be updated with a status of
+ Reviewing. Similarly, only Reviewing HITs can be reverted back to a
+ status of Reviewable.
"""
params = {'HITId' : hit_id,}
if revert:
params['Revert'] = revert
return self._process_request('SetHITAsReviewing', params)
- def disable_hit(self, hit_id):
+ def disable_hit(self, hit_id, response_groups=None):
"""
- Remove a HIT from the Mechanical Turk marketplace, approves all submitted assignments
- that have not already been approved or rejected, and disposes of the HIT and all
- assignment data.
+ Remove a HIT from the Mechanical Turk marketplace, approves all
+ submitted assignments that have not already been approved or rejected,
+ and disposes of the HIT and all assignment data.
- Assignments for the HIT that have already been submitted, but not yet approved or rejected, will be
- automatically approved. Assignments in progress at the time of the call to DisableHIT will be
- approved once the assignments are submitted. You will be charged for approval of these assignments.
- DisableHIT completely disposes of the HIT and all submitted assignment data. Assignment results
- data cannot be retrieved for a HIT that has been disposed.
+ Assignments for the HIT that have already been submitted, but not yet
+ approved or rejected, will be automatically approved. Assignments in
+ progress at the time of the call to DisableHIT will be approved once
+ the assignments are submitted. You will be charged for approval of
+ these assignments. DisableHIT completely disposes of the HIT and
+ all submitted assignment data. Assignment results data cannot be
+ retrieved for a HIT that has been disposed.
- It is not possible to re-enable a HIT once it has been disabled. To make the work from a disabled HIT
- available again, create a new HIT.
+ It is not possible to re-enable a HIT once it has been disabled.
+ To make the work from a disabled HIT available again, create a new HIT.
"""
params = {'HITId' : hit_id,}
+ # Handle optional response groups argument
+ if response_groups:
+ self.build_list_params(params, response_groups, 'ResponseGroup')
+
return self._process_request('DisableHIT', params)
def dispose_hit(self, hit_id):
"""
Dispose of a HIT that is no longer needed.
- Only HITs in the "reviewable" state, with all submitted assignments approved or rejected,
- can be disposed. A Requester can call GetReviewableHITs to determine which HITs are
- reviewable, then call GetAssignmentsForHIT to retrieve the assignments.
- Disposing of a HIT removes the HIT from the results of a call to GetReviewableHITs.
- """
+ Only HITs in the "reviewable" state, with all submitted
+ assignments approved or rejected, can be disposed. A Requester
+ can call GetReviewableHITs to determine which HITs are
+ reviewable, then call GetAssignmentsForHIT to retrieve the
+ assignments. Disposing of a HIT removes the HIT from the
+ results of a call to GetReviewableHITs. """
params = {'HITId' : hit_id,}
return self._process_request('DisposeHIT', params)
@@ -331,26 +364,31 @@ def expire_hit(self, hit_id):
"""
Expire a HIT that is no longer needed.
- The effect is identical to the HIT expiring on its own. The HIT no longer appears on the
- Mechanical Turk web site, and no new Workers are allowed to accept the HIT. Workers who
- have accepted the HIT prior to expiration are allowed to complete it or return it, or
- allow the assignment duration to elapse (abandon the HIT). Once all remaining assignments
- have been submitted, the expired HIT becomes "reviewable", and will be returned by a call
- to GetReviewableHITs.
+ The effect is identical to the HIT expiring on its own. The
+ HIT no longer appears on the Mechanical Turk web site, and no
+ new Workers are allowed to accept the HIT. Workers who have
+ accepted the HIT prior to expiration are allowed to complete
+ it or return it, or allow the assignment duration to elapse
+ (abandon the HIT). Once all remaining assignments have been
+ submitted, the expired HIT becomes"reviewable", and will be
+ returned by a call to GetReviewableHITs.
"""
params = {'HITId' : hit_id,}
return self._process_request('ForceExpireHIT', params)
def extend_hit(self, hit_id, assignments_increment=None, expiration_increment=None):
"""
- Increase the maximum number of assignments, or extend the expiration date, of an existing HIT.
+ Increase the maximum number of assignments, or extend the
+ expiration date, of an existing HIT.
- NOTE: If a HIT has a status of Reviewable and the HIT is extended to make it Available, the
- HIT will not be returned by GetReviewableHITs, and its submitted assignments will not
- be returned by GetAssignmentsForHIT, until the HIT is Reviewable again.
- Assignment auto-approval will still happen on its original schedule, even if the HIT has
- been extended. Be sure to retrieve and approve (or reject) submitted assignments before
- extending the HIT, if so desired.
+ NOTE: If a HIT has a status of Reviewable and the HIT is
+ extended to make it Available, the HIT will not be returned by
+ GetReviewableHITs, and its submitted assignments will not be
+ returned by GetAssignmentsForHIT, until the HIT is Reviewable
+ again. Assignment auto-approval will still happen on its
+ original schedule, even if the HIT has been extended. Be sure
+ to retrieve and approve (or reject) submitted assignments
+ before extending the HIT, if so desired.
"""
# must provide assignment *or* expiration increment
if (assignments_increment is None and expiration_increment is None) or \
@@ -367,8 +405,9 @@ def extend_hit(self, hit_id, assignments_increment=None, expiration_increment=No
def get_help(self, about, help_type='Operation'):
"""
- Return information about the Mechanical Turk Service operations and response group
- NOTE - this is basically useless as it just returns the URL of the documentation
+ Return information about the Mechanical Turk Service
+ operations and response group NOTE - this is basically useless
+ as it just returns the URL of the documentation
help_type: either 'Operation' or 'ResponseGroup'
"""
@@ -377,11 +416,13 @@ def get_help(self, about, help_type='Operation'):
def grant_bonus(self, worker_id, assignment_id, bonus_price, reason):
"""
- Issues a payment of money from your account to a Worker.
- To be eligible for a bonus, the Worker must have submitted results for one of your
- HITs, and have had those results approved or rejected. This payment happens separately
- from the reward you pay to the Worker when you approve the Worker's assignment.
- The Bonus must be passed in as an instance of the Price object.
+ Issues a payment of money from your account to a Worker. To
+ be eligible for a bonus, the Worker must have submitted
+ results for one of your HITs, and have had those results
+ approved or rejected. This payment happens separately from the
+ reward you pay to the Worker when you approve the Worker's
+ assignment. The Bonus must be passed in as an instance of the
+ Price object.
"""
params = bonus_price.get_as_params('BonusAmount', 1)
params['WorkerId'] = worker_id
@@ -414,7 +455,8 @@ def _process_response(self, response, marker_elems=None):
@staticmethod
def get_keywords_as_string(keywords):
"""
- Returns a comma+space-separated string of keywords from either a list or a string
+ Returns a comma+space-separated string of keywords from either
+ a list or a string
"""
if type(keywords) is list:
keywords = ', '.join(keywords)
@@ -477,7 +519,8 @@ def _has_expired(self):
class Assignment(BaseAutoResultElement):
"""
- Class to extract an Assignment structure from a response (used in ResultSet)
+ Class to extract an Assignment structure from a response (used in
+ ResultSet)
Will have attributes named as per the Developer Guide,
e.g. AssignmentId, WorkerId, HITId, Answer, etc
@@ -500,17 +543,20 @@ def endElement(self, name, value, connection):
class QuestionFormAnswer(BaseAutoResultElement):
"""
- Class to extract Answers from inside the embedded XML QuestionFormAnswers element inside the
- Answer element which is part of the Assignment structure
-
- A QuestionFormAnswers element contains an Answer element for each question in the HIT or
- Qualification test for which the Worker provided an answer. Each Answer contains a
- QuestionIdentifier element whose value corresponds to the QuestionIdentifier of a
- Question in the QuestionForm. See the QuestionForm data structure for more information about
- questions and answer specifications.
-
- If the question expects a free-text answer, the Answer element contains a FreeText element. This
- element contains the Worker's answer
+ Class to extract Answers from inside the embedded XML
+ QuestionFormAnswers element inside the Answer element which is
+ part of the Assignment structure
+
+ A QuestionFormAnswers element contains an Answer element for each
+ question in the HIT or Qualification test for which the Worker
+ provided an answer. Each Answer contains a QuestionIdentifier
+ element whose value corresponds to the QuestionIdentifier of a
+ Question in the QuestionForm. See the QuestionForm data structure
+ for more information about questions and answer specifications.
+
+ If the question expects a free-text answer, the Answer element
+ contains a FreeText element. This element contains the Worker's
+ answer
*NOTE* - currently really only supports free-text answers
"""

0 comments on commit ccfdc9e

Please sign in to comment.