REST1#
Rt - Python interface to Request Tracker API.
Description of Request Tracker REST API: http://requesttracker.wikia.com/wiki/REST
Provided functionality:
login to RT
logout
getting, creating and editing tickets
getting attachments
getting history of ticket
replying to ticket requestors
adding comments
getting and editing ticket links
searching
providing lists of last updated tickets
providing tickets with new correspondence
merging tickets
take tickets
steal tickets
untake tickets
- rt.rest1.DEFAULT_QUEUE = 'General'#
Default queue used.
- class rt.rest1.Rt(url: str, default_login: str | None = None, default_password: str | None = None, cookies: dict | None = None, proxy: str | None = None, default_queue: str = 'General', skip_login: bool = False, verify_cert: str | bool | None = True, http_auth: AuthBase | None = None)[source]#
API for Request Tracker according to http://requesttracker.wikia.com/wiki/REST.
Interface is based on REST architecture, which is based on HTTP/1.1 protocol. This module is therefore mainly sending and parsing special HTTP messages.
Note
Use only ASCII LF as newline (
\\n
). Time is returned in UTC. All strings returned are encoded in UTF-8 and the same is expected as input for string values.- RE_PATTERNS: Dict[str, Pattern] = {'attachments_list_pattern': re.compile('[^0-9]*(\\d+): (.+) \\((.+) / (.+)\\),?$'), 'attachments_pattern': re.compile('Attachments:'), 'bad_request_pattern': re.compile('.* 400 Bad Request$'), 'content_pattern': re.compile('Content:'), 'content_pattern_bytes': re.compile(b'Content:'), 'created_link_pattern': re.compile('.* Created link '), 'credentials_required_pattern': re.compile('.* 401 Credentials required$'), 'deleted_link_pattern': re.compile('.* Deleted link '), 'does_not_exist_pattern': re.compile('^# (?:Queue|User|Ticket) \\w* does not exist\\.$'), 'does_not_exist_pattern_bytes': re.compile(b'^# (?:Queue|User|Ticket) \\w* does not exist\\.$'), 'headers_pattern_bytes': re.compile(b'Headers:'), 'invalid_attachment_pattern_bytes': re.compile(b'^# Invalid attachment id: \\d+$'), 'links_updated_pattern': re.compile('^# Links for ticket [0-9]+ updated.$'), 'merge_successful_pattern': re.compile('^# Merge completed.|^Merge Successful$'), 'not_allowed_pattern': re.compile('^# You are not allowed to'), 'not_related_pattern': re.compile('^# Transaction \\d+ is not related to Ticket \\d+'), 'queue_pattern': re.compile('^# Queue (\\w*) (?:updated|created)\\.$'), 'requestors_pattern': re.compile('Requestors:'), 'status_pattern': re.compile('^\\S+ (\\d{3}) '), 'syntax_error_pattern': re.compile('.* 409 Syntax Error$'), 'ticket_created_pattern': re.compile('^# Ticket ([0-9]+) created\\.$'), 'update_pattern': re.compile('^# Ticket [0-9]+ updated.$'), 'user_pattern': re.compile('^# User ([0-9]*) (?:updated|created)\\.$')}#
- __init__(url: str, default_login: str | None = None, default_password: str | None = None, cookies: dict | None = None, proxy: str | None = None, default_queue: str = 'General', skip_login: bool = False, verify_cert: str | bool | None = True, http_auth: AuthBase | None = None) None [source]#
API initialization.
- Parameters:
url – Base URL for Request Tracker API. E.g.: http://tracker.example.com/REST/1.0/
default_login – Default RT login used by self.login if no other credentials are provided
default_password – Default RT password
proxy – Proxy server (string with http://user:password@host/ syntax)
default_queue – Default RT queue
skip_login – Set this option True when HTTP Basic authentication credentials for RT are in .netrc file. You do not need to call login, because it is managed by requests library instantly.
http_auth – Specify a http authentication instance, e.g. HTTPBasicAuth(), HTTPDigestAuth(), etc. to be used for authenticating to RT
- comment(ticket_id: str | int, text: str = '', cc: str = '', bcc: str = '', content_type: str = 'text/plain', files: List[Tuple[str, IO, str | None]] | None = None) bool [source]#
Adds comment to the given ticket.
Form of message according to documentation:
id: <ticket-id> Action: comment Text: the text comment second line starts with the same indentation as first Attachment: an attachment filename/path
Example:
>>> tracker = Rt('http://tracker.example.com/REST/1.0/', 'rt-username', 'top-secret') >>> attachment_name = sys.argv[1] >>> message_text = ' '.join(sys.argv[2:]) >>> ret = tracker.comment(ticket_id, text=message_text, ... files=[(attachment_name, open(attachment_name, 'rb'))]) >>> if not ret: ... print('Error: could not send attachment', file=sys.stderr) ... exit(1)
- Parameters:
ticket_id – ID of ticket to which comment belongs
text – Content of comment
content_type – Content type of comment, default to text/plain
files – Files to attach as multipart/form-data List of 2/3 tuples: (filename, file-like object, [content type])
- Returns:
True
Operation was successful
False
Sending failed (status code != 200)
- Raises:
BadRequestError – When ticket does not exist
- create_queue(Name: str, **kwargs: Any) int [source]#
Create queue (undocumented API feature).
- Parameters:
Name – Queue name (required)
kwargs – Optional fields to set (see edit_queue)
- Returns:
ID of new queue or False when create fails
- Raises:
BadRequestError – When queue already exists
InvalidUseError – When invalid fields are set
- create_ticket(Queue: str | object | None = None, files: List[Tuple[str, IO, str | None]] | None = None, **kwargs: Any) int [source]#
Create new ticket and set given parameters.
Example of message sended to
http://tracker.example.com/REST/1.0/ticket/new
:content=id: ticket/new Queue: General Owner: Nobody Requestor: somebody@example.com Subject: Ticket created through REST API Text: Lorem Ipsum
In case of success returned message has this form:
RT/3.8.7 200 Ok # Ticket 123456 created. # Ticket 123456 updated.
Otherwise:
RT/3.8.7 200 Ok # Required: id, Queue
list of some key, value pairs, probably default values.
- Parameters:
Queue – Queue where to create ticket
files – Files to attach as multipart/form-data List of 2/3 tuples: (filename, file-like object, [content type])
kwargs –
Other arguments possible to set:
Requestor, Subject, Cc, AdminCc, Owner, Status, Priority, InitialPriority, FinalPriority, TimeEstimated, Starts, Due, Text,… (according to RT fields)
Custom fields CF.{<CustomFieldName>} could be set with keywords CF_CustomFieldName.
- Returns:
ID of new ticket or
-1
, if creating failed
- create_user(Name: str, EmailAddress: str, **kwargs: Any) int | bool [source]#
Create user (undocumented API feature).
- Parameters:
Name – User name (login for privileged, required)
EmailAddress – Email address (required)
kwargs – Optional fields to set (see edit_user)
- Returns:
ID of new user or False when create fails
- Raises:
BadRequestError – When user already exists
InvalidUseError – When invalid fields are set
- edit_link(ticket_id: str | int, link_name: str, link_value: str | int, delete: bool = False) bool [source]#
Creates or deletes a link between the specified tickets (undocumented API feature).
- Parameters:
ticket_id – ID of ticket to edit
link_name – Name of link to edit (DependsOn, DependedOnBy, RefersTo, ReferredToBy, HasMember or MemberOf)
link_value – Either ticker ID or external link.
delete – if True the link is deleted instead of created
- Returns:
True
Operation was successful
False
Ticket with given ID does not exist or link to delete is not found
- Raises:
InvalidUseError – When none or more then one links are specified. Also when wrong link name is used.
- edit_queue(queue_id: str | int, **kwargs: Any) str | bool [source]#
Edit queue (undocumented API feature).
- Parameters:
queue_id – Identification of queue by name (str) or ID (int)
kwargs –
Other fields to edit from the following list:
Name
Description
CorrespondAddress
CommentAddress
InitialPriority
FinalPriority
DefaultDueIn
- Returns:
ID or name of edited queue or False when edit fails
- Raises:
BadRequestError – When queue does not exist
InvalidUseError – When invalid fields are set
- edit_ticket(ticket_id: str | int, **kwargs: Any) bool [source]#
Edit ticket values.
- Parameters:
ticket_id – ID of ticket to edit
kwargs –
Other arguments possible to set:
Requestors, Subject, Cc, AdminCc, Owner, Status, Priority, InitialPriority, FinalPriority, TimeEstimated, Starts, Due, Text,… (according to RT fields)
Custom fields CF.{<CustomFieldName>} could be set with keywords CF_CustomFieldName.
- Returns:
True
Operation was successful
False
Ticket with given ID does not exist or unknown parameter was set (in this case all other valid fields are changed)
- edit_ticket_links(ticket_id: str | int, **kwargs: Any) bool [source]#
Edit ticket links.
Warning
This method is deprecated in favour of edit_link method, because there exists bug in RT 3.8 REST API causing mapping created links to ticket/1. The only drawback is that edit_link cannot process multiple links all at once.
- Parameters:
ticket_id – ID of ticket to edit
kwargs – Other arguments possible to set: DependsOn, DependedOnBy, RefersTo, ReferredToBy, Members, MemberOf. Each value should be either ticker ID or external link. Int types are converted. Use empty string as value to delete existing link.
- Returns:
True
Operation was successful
False
Ticket with given ID does not exist or unknown parameter was set (in this case all other valid fields are changed)
- edit_user(user_id: str | int, **kwargs: Any) int | bool [source]#
Edit user profile (undocumented API feature).
- Parameters:
user_id – Identification of user by username (str) or user ID (int)
kwargs –
Other fields to edit from the following list:
Name
Password
EmailAddress
RealName
NickName
Gecos
Organization
Address1
Address2
City
State
Zip
Country
HomePhone
WorkPhone
MobilePhone
PagerPhone
ContactInfo
Comments
Signature
Lang
EmailEncoding
WebEncoding
ExternalContactInfoId
ContactInfoSystem
ExternalAuthId
AuthSystem
Privileged
Disabled
- Returns:
ID of edited user or False when edit fails
- Raises:
BadRequestError – When user does not exist
InvalidUseError – When invalid fields are set
- get_attachment(ticket_id: str | int, attachment_id: str | int) dict | None [source]#
Get attachment.
- Parameters:
ticket_id – ID of ticket
attachment_id – ID of attachment for obtain
- Returns:
Attachment as dictionary with these keys:
Transaction
ContentType
Parent
Creator
Created
Filename
Content (bytes type)
Headers
MessageId
ContentEncoding
id
Subject
All these fields are strings, just ‘Headers’ holds another dictionary with attachment headers as strings e.g.:
Delivered-To
From
Return-Path
Content-Length
To
X-Seznam-User
X-QM-Mark
Domainkey-Signature
RT-Message-ID
X-RT-Incoming-Encryption
X-Original-To
Message-ID
X-Spam-Status
In-Reply-To
Date
Received
X-Country
X-Spam-Checker-Version
X-Abuse
MIME-Version
Content-Type
Subject
Warning
Content-Length parameter is set after opening ticket in web interface!
Set of headers available depends on mailservers sending emails not on Request Tracker!
Returns None if ticket or attachment does not exist.
- Raises:
UnexpectedMessageFormatError – Unexpected format of returned message.
- get_attachment_content(ticket_id: str | int, attachment_id: str | int) bytes | None [source]#
Get content of attachment without headers.
This function is necessary to use for binary attachment, as it can contain
\\n
chars, which would disrupt parsing of message ifget_attachment()
is used.Format of message:
RT/3.8.7 200 Ok\n\nStart of the content...End of the content\n\n\n
- Parameters:
ticket_id – ID of ticket
attachment_id – ID of attachment
- Returns: Bytes with content of attachment or None if ticket or
attachment does not exist.
- get_attachments(ticket_id: str | int) List[Tuple[str, str, str, str]] | None [source]#
Get attachment list for a given ticket.
- Parameters:
ticket_id – ID of ticket
- Returns:
List of tuples for attachments belonging to given ticket. Tuple format: (id, name, content_type, size) Returns None if ticket does not exist.
- get_attachments_ids(ticket_id: str | int) List[int] | None [source]#
Get IDs of attachments for given ticket.
- Parameters:
ticket_id – ID of ticket
- Returns:
List of IDs (type int) of attachments belonging to given ticket. Returns None if ticket does not exist.
- get_history(ticket_id: str | int, transaction_id: str | int | None = None) List[dict] | None [source]#
Get set of history items.
- Parameters:
ticket_id – ID of ticket
transaction_id – If set to None, all history items are returned, if set to ID of valid transaction just one history item is returned
- Returns:
List of history items ordered increasingly by time of event. Each history item is dictionary with following keys:
Description, Creator, Data, Created, TimeTaken, NewValue, Content, Field, OldValue, Ticket, Type, id, Attachments
All these fields are strings, just ‘Attachments’ holds list of pairs (attachment_id,filename_with_size).
Returns None if ticket or transaction does not exist.
- Raises:
UnexpectedMessageFormatError – Unexpected format of returned message.
- get_links(ticket_id: str | int) Dict[str, List[str]] | None [source]#
Gets the ticket links for a single ticket.
- Parameters:
ticket_id – ticket ID
- Returns:
Links as lists of strings in dictionary with these keys (just those which are defined):
id
Members
MemberOf
RefersTo
ReferredToBy
DependsOn
DependedOnBy
None is returned if ticket does not exist.
- Raises:
UnexpectedMessageFormatError – In case that returned status code is not 200
- get_queue(queue_id: str | int) Dict[str, str] | None [source]#
Get queue details.
- Parameters:
queue_id – Identification of queue by name (str) or queue ID (int)
- Returns:
Queue details as strings in dictionary with these keys if queue exists (otherwise None):
id
Name
Description
CorrespondAddress
CommentAddress
InitialPriority
FinalPriority
DefaultDueIn
- Raises:
UnexpectedMessageFormatError – In case that returned status code is not 200
- get_short_history(ticket_id: str | int) List[Tuple[int, str]] | None [source]#
Get set of short history items.
- Parameters:
ticket_id – ID of ticket
- Returns:
List of history items ordered increasingly by time of event. Each history item is a tuple containing (id, Description). Returns None if ticket does not exist.
- get_ticket(ticket_id: str | int) dict | None [source]#
Fetch ticket by its ID.
- Parameters:
ticket_id – ID of demanded ticket
- Returns:
Dictionary with key, value pairs for ticket with ticket_id or None if ticket does not exist. List of keys:
id
numerical_id
Queue
Owner
Creator
Subject
Status
Priority
InitialPriority
FinalPriority
Requestors
Cc
AdminCc
Created
Starts
Started
Due
Resolved
Told
TimeEstimated
TimeWorked
TimeLeft
- Raises:
UnexpectedMessageFormatError – Unexpected format of returned message.
- get_user(user_id: str | int) Dict[str, str] | None [source]#
Get user details.
- Parameters:
user_id – Identification of user by username (str) or user ID (int)
- Returns:
User details as strings in dictionary with these keys for RT users:
Lang
RealName
Privileged
Disabled
Gecos
EmailAddress
Password
id
Name
Or these keys for external users (e.g. Requestors replying to email from RT:
RealName
Disabled
EmailAddress
Password
id
Name
None is returned if user does not exist.
- Raises:
UnexpectedMessageFormatError – In case that returned status code is not 200
- last_updated(since: str, queue: str | object | None = None) List[dict] [source]#
Obtains tickets changed after given date.
- Parameters:
since – Date as string in form ‘2011-02-24’
queue – Queue where to search
- Returns:
List of tickets with LastUpdated parameter later than since ordered in decreasing order by LastUpdated. Each tickets is dictionary, the same as in
get_ticket()
.
- login(login: str | None = None, password: str | None = None) bool [source]#
Login with default or supplied credentials.
Note
Calling this method is not necessary when HTTP basic or HTTP digest_auth authentication is used and RT accepts it as external authentication method, because the login in this case is done transparently by requests module. Anyway this method can be useful to check whether given credentials are valid or not.
- Parameters:
login – Username used for RT, if not supplied together with password
default_login
anddefault_password
are used insteadpassword – Similarly as login
- Returns:
True
Successful login
False
Otherwise
- Raises:
AuthorizationError – In case that credentials are not supplied neither during inicialization or call of this method.
- logout() bool [source]#
Logout of user.
- Returns:
True
Successful logout
False
Logout failed (mainly because user was not login)
- merge_ticket(ticket_id: str | int, into_id: str | int) bool [source]#
Merge ticket into another (undocumented API feature).
- Parameters:
ticket_id – ID of ticket to be merged
into_id – ID of destination ticket
- Returns:
True
Operation was successful
False
Either origin or destination ticket does not exist or user does not have ModifyTicket permission.
- new_correspondence(queue: str | object | None = None) List[dict] [source]#
Obtains tickets changed by other users than the system one.
- Parameters:
queue – Queue where to search
- Returns:
List of tickets which were last updated by other user than the system one ordered in decreasing order by LastUpdated. Each ticket is dictionary, the same as in
get_ticket()
.
- reply(ticket_id: str | int, text: str = '', cc: str = '', bcc: str = '', content_type: str = 'text/plain', files: List[Tuple[str, IO, str | None]] | None = None) bool [source]#
Sends email message to the contacts in
Requestors
field of given ticket with subject as is set inSubject
field.Form of message according to documentation:
id: <ticket-id> Action: correspond Text: the text comment second line starts with the same indentation as first Cc: <...> Bcc: <...> TimeWorked: <...> Attachment: an attachment filename/path
- Parameters:
ticket_id – ID of ticket to which message belongs
text – Content of email message
content_type – Content type of email message, default to text/plain
cc – Carbon copy just for this reply
bcc – Blind carbon copy just for this reply
files – Files to attach as multipart/form-data List of 2/3 tuples: (filename, file-like object, [content type])
- Returns:
True
Operation was successful
False
Sending failed (status code != 200)
- Raises:
BadRequestError – When ticket does not exist
- search(Queue: str | object | None = None, order: str | None = None, raw_query: str | None = None, Format: str = 'l', Fields: List[str] | None = None, **kwargs: Any) List[dict] [source]#
Search arbitrary needles in given fields and queue.
Example:
>>> tracker = Rt('http://tracker.example.com/REST/1.0/', 'rt-username', 'top-secret') >>> tracker.login() >>> tickets = tracker.search(CF_Domain='example.com', Subject__like='warning') >>> tickets = tracker.search(Queue='General', order='Status', raw_query="id='1'+OR+id='2'+OR+id='3'")
- Parameters:
Queue – Queue where to search. If you wish to search across all of your queues, pass the ALL_QUEUES object as the argument.
order – Name of field sorting result list, for descending order put - before the field name. E.g. -Created will put the newest tickets at the beginning
raw_query – A raw query to provide to RT if you know what you are doing. You may still pass Queue and order kwargs, so use these instead of including them in the raw query. You can refer to the RT query builder. If passing raw_query, all other \**kwargs will be ignored.
Format –
Format of the query:
i: only id fields are populated
s: only id and subject fields are populated
l: multi-line format, all fields are populated
kwargs –
Other arguments possible to set if not passing raw_query:
Requestors, Subject, Cc, AdminCc, Owner, Status, Priority, InitialPriority, FinalPriority, TimeEstimated, Starts, Due, Text,… (according to RT fields)
Custom fields CF.{<CustomFieldName>} could be set with keywords CF_CustomFieldName.
To alter lookup operators you can append one of the following endings to each keyword:
__exact for operator = (default) __notexact for operator != __gt for operator > __lt for operator < __like for operator LIKE __notlike for operator NOT LIKE __is for operator IS __isnot for operator IS NOT
Setting values to keywords constrain search result to the tickets satisfying all of them.
- Returns:
List of matching tickets. Each ticket is the same dictionary as in
get_ticket()
\.- Raises:
UnexpectedMessageFormatError: Unexpected format of returned message. InvalidQueryError: If raw query is malformed
- static split_header(line: str) Sequence[str] [source]#
Split a header line into field name and field value.
Note that custom fields may contain colons inside the curly braces, so we need a special test for them.
- Parameters:
line – A message line to be split.
- Returns:
(Field name, field value) tuple.
- steal(ticket_id: str | int) bool [source]#
Steal ticket.
- Parameters:
ticket_id – ID of ticket to be merged
- Returns:
True
Operation was successful
False
Either the ticket does not exist or user does not have StealTicket permission.