Giter Site home page Giter Site logo

rallyresttoolkitforpython's Introduction

pyral - A Python toolkit for the Rally REST API

The pyral package enables you to push, pull and otherwise wrangle the data in your Rally subscription using the popular and productive Python language. The pyral package provides a smooth and easy to use veneer on top of the Rally REST Web Services API using JSON.

Rally has created a Python package that you can quickly leverage to interact with the data in your subscription via the REST web services API. You can create, read, update, and delete the common artifacts and other entities via the Python toolkit for Rally.

Files are available at the download page .

The git repository is available at https://github.com/RallyTools/RallyRestToolkitForPython

If you want to pull down the latest release from standard Python package repository (pypi.python.org) and install the package, the easiest way is to use pip, the Python package installation utility.:

pip install pyral

Alternatively, if you've got the tar.gz or zip distribution on hand, as long as you've satisfied the dependency requirement on the requests package, you can use the setup mechanism. Obtain the requests package and install it according to that package's directions. Use of requests-2.28.x or better is recommended for use with pyral. The requests package can be found via the Python Package Index site (http://pypi/python.org/index). The most recent release of pyral (1.6.0) has been tested using requests 2.31.0.

Unpack the pyral distribution file (zip or tar.gz) and then install the pyral package.

python setup.py install

Use whatever setup options you need for your particular Python environment.

Fire up a command line Python interpreter. Attempt to import the relevant packages.

$ python
Python 3.11.5 [other Python interpreter info elided ...]
>> import requests
>> import pyral
>> pyral.__version__
(1, 6, 0)

Since Python is a very flexible and extensible language, we were able to make access to the object model extremely simple. For example, if you have a a UserStory instance returned by a pyral operation assigned to the name story, the following code iterates over the tasks.

for task in story.Tasks:
   print task.Name

There is no need to make a separate call to fetch all the tasks for the story. When you follow domain model attributes in the Python code, the Python toolkit for Rally REST API machinery automatically loads in the necessary objects for you.

The complete documentation for the Python toolkit for Rally REST API is in the doc/build/html subdirectory in the repository. The rendered version of this is also available at http://pyral.readthedocs.io/en/latest/

Common setup code

import sys
from pyral import Rally, rallyWorkset
options = [arg for arg in sys.argv[1:] if arg.startswith('--')]
args    = [arg for arg in sys.argv[1:] if arg not in options]
server, user, password, apikey, workspace, project = rallyWorkset(options)
rally = Rally(server, user, password, apikey=apikey, workspace=workspace, project=project)
Show a TestCase identified by the FormattedID value.
Copy the above boilerplate and the following code fragment and save it in a file named gettc.py
query_criteria = 'FormattedID = "%s"' % args[0]
response = rally.get('TestCase', fetch=True, query=query_criteria)
if response.errors:
    sys.stdout.write("\n".join(errors))
    sys.exit(1)
for testCase in response:  # there should only be one qualifying TestCase
    print "%s %s %s %s" % (testCase.Name, testCase.Type,
                           testCase.DefectStatus, testCase.LastVerdict)
  • Run it by providing the FormattedID value of your targeted TestCase as a command line argument

    python gettc.py TC1184

Get a list of workspaces and projects for your subscription
Copy the above boilerplate and the following code fragment and save it in a file called wksprj.py
workspaces = rally.getWorkspaces()
for wksp in workspaces:
    print "%s %s" % (wksp.oid, wksp.Name)
    projects = rally.getProjects(workspace=wksp.Name)
    for proj in projects:
        print "    %12.12s  %s" % (proj.oid, proj.Name)
  • Run the script

    python wksprj.py

Create a new Defect
Copy the above boilerplate and the following code fragment and save it in a file called crdefect.py
proj = rally.getProject()

# get the first (and hopefully only) user whose DisplayName is 'Sartorious Submitter'
user = rally.getUserInfo(name='Sartorius Submitter').pop(0)

defect_data = { "Project" : proj.ref, "SubmittedBy" : user.ref,
                "Name" : name, "Severity" : severity, "Priority" : priority,
                "State" : "Open", "ScheduleState" : "Defined",
                "Description" : description }
try:
    defect = rally.create('Defect', defect_data)
except Exception, details:
    sys.stderr.write('ERROR: %s \n' % details)
    sys.exit(1)
print "Defect created, ObjectID: %s  FormattedID: %s" % (defect.oid, defect.FormattedID)
  • Run the script

    python crdefect.py <Name> <severity> <priority> <description>

    making sure to provide valid severity and priority values for your workspace

Update an existing Defect
Copy the above boilerplate and the following code fragment and save it in a file called updefect.py .
 defectID, customer, target_date, notes = args[:4]
 # target_date must be in ISO-8601 format "YYYY-MM-DDThh:mm:ssZ"

 defect_data = { "FormattedID" : defectID,
                 "Customer"    : customer,
                 "TargetDate"  : target_date,
                 "Notes"       : notes
               }
 try:
     defect = rally.update('Defect', defect_data)
 except Exception, details:
     sys.stderr.write('ERROR: %s \n' % details)
     sys.exit(1)

print "Defect %s updated" % defect.FormattedID
  • Run the script

    python updefect.py <Defect FormattedID> <customer> <target_date> <notes text...>

The pyral package uses a priority chain of files, environment variables and command line arguments to set the configuration context when an instance of the Rally class is created. See the complete documentation for detailed information on this mechanism. Here's a brief description of how you can specify a configuration when you create an instance of the Rally class.

Configuration file settings

Config file item Description
SERVER Rally server (example rally1.rallydev.com)
USER Rally subscription UserName value
PASSWORD password for the Rally subscription UserName
APIKEY Rally API Key value
WORKSPACE Rally Workspace
PROJECT Rally Project

The item names in config files are case sensitive.

Command line options

Command line option Description
--rallyConfig=<config_file_name> name of the file with settings for pyral
--config=<config_file_name> ditto
--conf=<config_file_name> ditto
--cfg=<config_file_name> ditto
--rallyUser=<foo> your Rally UserName
--rallyPassword=<bar> password associated with the Rally UserName
--apikey=<APIKey> valid Rally API Key value
--rallyWorkspace=<bar> Workspace in Rally you want to interact with
--rallyProject=<bar> Project in Rally you want to interact with
  • Python 3.9, 3,10, 3.11 or 3.12 (this package not tested with earlier versions of Python 3.x)
  • The requests package, 2.28.1 or better, requests 2.31.0 or beyond is recommended.
1.6.0
Eliminated use of six package. Added support for Risk, Objective, KeyResult and CapacityPlan* entities. Fixed bug in restapi.getAllUsers that prevented retrieval of Users beyond the first chunk Adjusted restapi.py treatment of headers to allow multiple pyral.Rally instances (could be various users...). Explicitly state support for Python 3.9, 3.10, 3.11 and 3.12 Drop any mention of support for versions 3.8 and earlier.
1.5.2
Fixed query builder so that multi-condition queries thet include subset or range conditions are constructed correctly. Dropped all code related to ping functionality.
1.5.1
Fixed query builder to accommodate subset criteria (in | !in) and range criteria (between | !between). Dropped mention of Python 3.5 as a supported version in PKG-INFO. Added mention of Python 3.9 as a supported version in PKG-INFO. Excised all mentions of AgileCentral in the docs, replaced by 'Rally'.
1.5.0
Dropped all support for Python 2.7 constructs. Validated support for Python 3.7 and 3.8. Fixed defect where attachments were not returned from getAttachments method. Fixed defect where the creation or update of a custom PortfolioItem sub-type did not return a valid pyral instance of the sub-type. Fixed defect in returning correct number of items when the start index is specified as an integer. Fixed defect where a feature item could not be added to a Milestones collection Fixed defect in query construction (and results) when a target attribute value contains a '&' character.
1.4.2
Fixed defect in returning RallyRESTResponse when pagesize set to 1
1.4.1
Support for TestFolderStatus attribute in TestFolder. Fixed defect in addCollectionItems
1.4.0
Support for PullRequest entity object (subclassed from Connection).
1.3.2
Allow for initial connection using a workspace name containing chars that need to be urlencoded.
1.3.1
Adjusted getAllowedValues so that custom fields with an allowedValues endpoint get resolved. Disqualifed a group of standard attributes whose allowedValue is of type COLLECTION when retrieving allowed values in SchemaItem.complete(). This is primarily relevant only to attributes defined as Drop Down List or Multi Value Drop Down List. Fixed mechanism of supplying headers dict to Rally instantiation so that the X-RallyIntegration* headers get overwritten with supplied headers (for name, vendor, version) to better identify the origin of the integration. Updated official name to reference Agile Central in setup.py, mention threads keyword arg in the get method in the the interface.rst file.
1.3.0
Introduced automatic multi-threading for Rally.get operation to speed up retrieval of large result sets. Implemented step two of the Pinger deprecation plan, ping=False is the new default. Increased default page size to 500. Maximum useful page size limit is 2000 but 1000 seems to be the sweet spot for multithreading requests. Fixed Rally.getAllUsers so that non subscription admin accounts can see the user list. Updated recommendation for version of requests package.
1.2.4
Fixed handling of projectScopeUp and projectScopeDown keyword arguments for get operation. Fixed Peristable's __getattr__ method to more properly handle getting the salient item out of a response to a getResourceByOID request when the item retrieved is a PortfolioItem sub-type. Fixed defect in SchemaItemAttribute where self._allowed_values_resolved was not always set. Fixed defect in RallyRestResponse in __repr__ method where on a response that has no qualifying items an attempt is made to get the Results out of the returned response without going through the QueryResult key.
1.2.3
Fixed restapi.py Rally.getAllowedValues method to accommodate custom fields Allow attribute payload for put and post to have a list of pyral.Entity instances as values for an attribute that is of type COLLECTION.
1.2.2
Allow for disambiguating Project amongst name duplications by means of using fully qualified path. Incorporated suggestion on preserving case name of custom PortfolioItem sub-item. Fixed discrepancy of docs versus code on default pagesize, now is actually 200 everywhere. Fix location of download package in GitHub repo.
1.2.1
Added mention that the six package is required. Fixed context setup for proper handling when a user has no default workspace/project settings. Corrected handling of allowedValues for attributes when the single allowedValue is a boolean value. Added an allowedValues.py example script.
1.2.0

Support for Python 3.5.x Begin deprecation sequence for pinging the Rally server before the connection attempt, initially with this version, allow option on instantiation to bypass ping. Added ability to rankAbove, rankBelow, rankToTop, rankToBottom for an Artifact. Fixed defect where user has no default workspace or project.

addAttachment now correctly handles binary file, attachment size limit increased to 50MB to match Agile Central limit. Exception generated when running getAllUsers when credentials are for non Subscription/Workspace Administrator has been fixed. Added ability to work with a single Workspace, which has beneficial performance effect for Subscriptions with a large number of Workspaces. Modified internal attribute handling to limit calls to get attribute's allowed values to qualifying attribute types. Added examples/updtag.py script.

see the VERSIONS file for information pertaining to older releases

  • Dynamically construct the Rally schema class hierarchy economically.

BSD3-style license. Copyright (c) 2018-2024 Broadcom, Inc., 2015-2018 CA Technologies, 2010-2015 Rally Software Development.

See the LICENSE file provided with the source distribution for full details.

None. See the LICENSE file for full text regarding this issue.

The use of this package is on an as-is basis and there is no official support offered by Broadcom. The author of this module periodically checks the GitHub repository issues for this package in the interests of providing defect fixes and small feature enhancements as time permits, but is not obligated to respond or take action. Posts to Stack Overflow (http://stackoverflow.com/questions/ask?tags=rally) are another avenue to engage others who have some exposure to pyral and might be able to offer useful information.

  • GitHub for repository hosting services.
  • ReadTheDocs for documentation hosting services.

rallyresttoolkitforpython's People

Contributors

ajaxodessa avatar annerajb avatar benroy avatar jimpriest avatar klehman-rally avatar mjmdavis avatar pgacv2 avatar ssbarnea avatar virtualsnake avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rallyresttoolkitforpython's Issues

KeyError: 'Results'

Using v1.1.1

Making a simple script to print Defect names. The first defects prints fine, however the second receives an error.

Traceback (most recent call last):
File "simple.py", line 21, in
print response
File "C:\Python27\lib\site-packages\pyral\rallyresp.py", line 378, in repr
(self.request_type, self.resultCount, self.content['Results'])
KeyError: 'Results'

Here's the code I'm using, not sure if you will need it. Let me know if you need my log as well.

import sys
from pyral import Rally, rallyWorkset, rallySettings

username = raw_input('Username: ')
pwd = raw_input('Password: ')

rally = Rally('rally1.rallydev.com', username, pwd)
rally.enableLogging('mypyral.log')

This Defect works.

response = rally.get('Defect', fetch=True, query='FormattedID = DE3179')
print response
for story in response:
print story.Name

This Defect does not.

response = rally.get('Defect', fetch=True, query='FormattedID = DE3557')
print response
for story in response:
print story.Name

AttributeError: User instance has no attribute: 'UserProfile'

How to reproduce:

import sys
from pyral import Rally, rallyWorkset

options = [opt for opt in sys.argv[1:] if opt.startswith('--')]
server, user, password, apikey, workspace, project = rallyWorkset(options)
print " ".join(['|%s|' % opt for opt in [server, user, password, apikey, workspace, project]])
rally = Rally(server, user, password, workspace=workspace, project=project)
users = rally.getAllUsers()


Traceback:
...
File "/Library/Python/2.7/site-packages/pyrallei/restapi.py", line 572, in getAllUsers
if prof._ref == user.UserProfile._ref]
File "/Library/Python/2.7/site-packages/pyrallei/entity.py", line 159, in getattr
raise AttributeError(description)
AttributeError: User instance has no attribute: 'UserProfile'


pyral 1.1.0/python 2.7.6/Rally API 2.0

getItem returns "No item found for Defect DE75386" but this defect exists

For most defects, test cases and such the above messages is returned if I try to get the item.
It is only very rarely that the correct response is returned.
I think it depends on maybe the project or some sort of filter but when I add the project to the rally login it returns a 404 error.
Would this not work just like the search function ie independent of project?
I do not want to modify, I only want to get states and other attributes.

Also if I dont specify a specific defect and print few I am able to query that particular defect without setting a project but when I set the project in which the defect is filed I get the 404 error again

I believe this was a user error - sorry

StopIteration issue

Hi everybody, sorry for interruption, but I am a new in pyral and I always get this kind of error during creation connection. Could you help me, please?

# python2.7 ./rally1.py 
Traceback (most recent call last):
  File "rally1.py", line 2, in <module>
    rally = Rally("rally1.rallydev.com", user="[email protected]", password="password")
  File "/usr/lib/python2.7/site-packages/pyral/restapi.py", line 228, in __init__
    self.contextHelper.check(self.server)
  File "/usr/lib/python2.7/site-packages/pyral/context.py", line 222, in check
    self._getDefaults(response)
  File "/usr/lib/python2.7/site-packages/pyral/context.py", line 262, in _getDefaults
    user = response.next()
  File "/usr/lib/python2.7/site-packages/pyral/rallyresp.py", line 264, in next
    raise StopIteration
StopIteration

# cat rally1.py 
from pyral import Rally
rally = Rally("rally1.rallydev.com", user="[email protected]", password="password")

>>> pyral.__version__
(1, 1, 1)
>>> requests.__version__
'2.9.1'

I have tried script from here #38 and have got the following answer:

$ ./basic.py 
https://rally1.rallydev.com/slm/webservice/v2.0/Subscription?fetch=true&pagesize=200&start=1
200
Request round-trip time:    1.00 secs

RESPONSE HEADER
{'Content-Length': '578', 'X-XSS-Protection': '1; mode=block', 'CF-RAY': '28bd9083110b0893-FRA', 'RallyRequestID': 'qd-app-061obufvs42w87131r2i6wogw1e.qd-app-06609127', 'Content-Encoding': 'gzip', 'Set-Cookie': '__cfduid=d0ac345c14dcb55664cdd586b52239d5b1459361910; expires=Thu, 30-Mar-17 18:18:30 GMT; path=/; domain=.rallydev.com; HttpOnly, JSESSIONID=qd-app-061obufvs42w87131r2i6wogw1e.qd-app-06;Path=/;Secure;HttpOnly, ZSESSIONID=p0vi1sXISKCjIHrySc1hPunLTDxdYU4SlfU0iRGH8XI;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SUBBUCKETID=590;Path=/;Domain=rally1.rallydev.com;Secure;HttpOnly, SERVERID=eef0381130fdee6ad45f9214be2b5a10994893f1; path=/', 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains', 'Vary': 'Accept-Encoding', 'Server': 'cloudflare-nginx', 'Connection': 'keep-alive', 'ETag': '"0ce1684f024cdde0d0046a377ed4e27f9"', 'Cache-Control': 'private,max-age=0,must-revalidate', 'Date': 'Wed, 30 Mar 2016 18:18:30 GMT', 'P3P': 'CP="NON DSP COR CURa PSAa PSDa OUR NOR BUS PUR COM NAV STA"', 'Content-Type': 'application/json;  charset=utf-8', 'Expires': 'Thu, 01 Jan 1970 00:00:00 GMT'}

RESPONSE BODY
{"Subscription": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "_ref": "https://rally1.rallydev.com/slm/webservice/v2.0/subscription/3631859928", "_refObjectUUID": "60ab78be-acac-4d0c-872d-562d336de916", "_objectVersion": "41", "_refObjectName": "Company Name", "CreationDate": "2011-06-14T16:46:40.186Z", "_CreatedAt": "Jun 14, 2011", "ObjectID": 3631859928, "ObjectUUID": "60ab78be-acac-4d0c-872d-562d336de916", "VersionId": "41", "ApiKeysEnabled": true, "EmailEnabled": true, "ExpirationDate": null, "JSONPEnabled": true, "MaximumCustomUserFields": -1, "MaximumProjects": -1, "Modules": "Integration Hub,Rally Portfolio Manager,HP Integration,IBM Integration,Rally Idea Manager,Rally Quality Manager,Rally Support Manager,Rally Time Tracker,SSO,IP Restriction,Extension Whitelist", "Name": "Company Name", "PasswordExpirationDays": 0, "PreviousPasswordCount": 0, "ProjectHierarchyEnabled": true, "SessionTimeoutSeconds": null, "StoryHierarchyEnabled": true, "StoryHierarchyType": "Unlimited", "SubscriptionID": 6590, "SubscriptionType": "Unlimited", "Workspaces": {"_rallyAPIMajor": "2", "_rallyAPIMinor": "0", "_ref": "https://rally1.rallydev.com/slm/webservice/v2.0/Subscription/3631859928/Workspaces", "_type": "Workspace", "Count": 1}, "Errors": [], "Warnings": []}}

Thank you.

AttributeError: 'RallyRESTResponse' object has no attribute '_served

Traceback (most recent call last):
File "./feature_rollup_spreadsheet.py", line 729, in
sys.exit(main())
File "./feature_rollup_spreadsheet.py", line 645, in main
for testcase in testcases:
File "/usr/lib/python2.6/site-packages/pyral/rallyresp.py", line 255, in next
if (self._served >= self._servable) or (self._limit and self._served >= self._limit):
AttributeError: 'RallyRESTResponse' object has no attribute '_served'

PyPi links broken, package not uploaded

The PyPi page for pyral contains important dead links:

Home Page: http://dev.developers.rallydev.com/rally-rest-toolkit-python
Download URL: http://dev.developers.rallydev.com/sites/default/files/multimedia/pyral-0.8.9.zip

In fact, at present, these should be http://developer.rallydev.com/help/python-toolkit-rally-rest-api and http://developer.rallydev.com/help/sites/default/files/multimedia/pyral-0.8.9.zip. (Option 1: correct PyPi; option 2, which should also be done: make those links work once more, others are sure to use the same links.)

It would also be good if the packages were actually uploaded to PyPi rather than just linked to.

While I'm here, I would also like to see the package renamed from pyral to rally. Is there a reason it's not simply called rally?

unable to install using python3 with pip3 install --user pyral

Installing collected packages: pyral
Running setup.py install for pyral
error: can't combine user with prefix, exec_prefix/home, or install_(plat)base
Complete output from command /usr/local/opt/python3/bin/python3.4 -c "import setuptools, tokenize;file='/private/var/folders/x5/vm_kq27d0hb17c7vp7tfk32h0000gn/T/pip_build_sorins/pyral/setup.py';exec(compile(getattr(tokenize, 'open', open)(file).read().replace('\r\n', '\n'), file, 'exec'))" install --record /var/folders/x5/vm_kq27d0hb17c7vp7tfk32h0000gn/T/pip-e7tg2u_x-record/install-record.txt --single-version-externally-managed --compile --user:
running install

error: can't combine user with prefix, exec_prefix/home, or install_(plat)base

Attribute error User instance has no attribute 'UserProfile' in function getAllUsers

The following block of code returns an error when the user has no attribute 'UserProfile'.

restapi.py, lines 571 to 575:

            # get any matching user profiles (aka mups), there really should only be 1 matching...
            mups = [prof for prof in profiles 
                          if hasattr(user, 'UserProfile') and prof._ref == user.UserProfile._ref] 
            if not mups:
                problem = "unable to find a matching UserProfile record for User: %s  UserProfile: %s"
                warning("%s" % (problem % (user.DisplayName, user.UserProfile)))
                continue

If the user has no attribute, 'UserProfile', the program enter in the condition "if no mups"; the line " warning(...)" raises then an error instead of a warning.

pyral with Release name containing paren returns error

When I create a query and the Release as a paren in the name, the server returns an error:

422 Could not parse: Unknown operator ")"

Release Name: 8.5 (Blah and Stuff)
Query String: 'Name = "8.5 (Blah and Stuff)"'

addAttachment() results in RallyRESTAPIError (422 Could not convert ...)

The Base64 encoding used by pyral can result in the Rally server rejecting attachments:

File "/usr/local/lib/python2.7/dist-packages/pyral/restapi.py", line 970, in put
    raise RallyRESTAPIError('%s %s' % (response.status_code, desc))
pyral.restapi.RallyRESTAPIError: 422 Could not convert:  : value to convert :

This appears to be resolved by switching from the base64 "legacy" interface to the Python > 2.4 API. At restapi.py:1309:

@@ -1306,8 +1306,8 @@ class Rally(object):

         contents = ''
         with open(filename, 'r') as af:
-            contents = base64.encodestring(af.read())
-            
+            contents = base64.b64encode(af.read())
+

Api Key Proxy Issue

I am trying to replace my old username/password Rally authentication with Rally API Keys. I'm using pyral 1.1.1 and requests 2.3.0 on a redhat server.

server, user, password, workspace, proj = rallySettings(options) rally = Rally(server, user, password)

to

rally = Rally(server='rally1.rallydev.com', apikey='SECRET_KEY')

When I made the change, I started getting errors like: ('Cannot connect to proxy.', gaierror(-5, 'No address associated with hostname')).

If I switch back to the old user/password route, it works just fine.

Here's how I am setting the proxy:

proxy = "http://internal.proxy.com:port"
os.environ['HTTPS_PROXY'] = proxy
os.environ['https_proxy'] = proxy
os.environ['HTTP_PROXY'] = proxy

Looking at the web commands being issued, I can see healthy behavior which looks like:

https://rally1.rallydev.com/slm/webservice/v2.0/User?fetch=true&query=(UserName%20%3D%20%22user%40company.com%22)&pagesize=100&start=1 120 <Response [200]>
https://rally1.rallydev.com/slm/webservice/v2.0/Subscription?fetch=true&pagesize=100&start=1 120 <Response [200]> https://rally1.rallydev.com/slm/webservice/v2.0/subscription/1904178192/Workspaces?fetch=true&query=(State = Open)&pagesize=200&start_index=1?pagesize=200&start=1 120 <Response [200]>
https://rally1.rallydev.com/slm/webservice/v2.0/Workspace/1904178204/Projects?fetch="ObjectID,Name,State"&pagesize=200&start_index=1?pagesize=200&start=1 120 <Response [200]>

With the API key turned on, I see:
https://rally1.rallydev.com/slm/webservice/v2.0/User?fetch=true&pagesize=100&start=1 120 <Response [200]>
https://rally1.rallydev.com/slm/webservice/v2.0/Subscription?fetch=true&pagesize=100&start=1 120 ('Cannot connect to proxy.', gaierror(-5, 'No address associated with hostname'))

So it succeeds behind a proxy for the first query, but not the second.

I can connect using curl:

curl -x httpL//proxy.com:80 --header "zsessionid:_apiKey " -H "Content-Type: application/json" https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement?workspace=workspace/ 12352608129

Need for addAttachments to support TestCaseResult

See: http://stackoverflow.com/questions/23414094/adding-attachments-to-testcaseresults-using-pyral-0-9-3

The issue is that the addAttachment method for pyral's restapi, sets a ref to the "Artifact" attribute of the Attachment object, as shown following (lines 1241 thru 1251 of restapi):

attachment_info = { "Name"        :  attachment_file_name,
                    "Content"     :  ac.ref,       # ref to AttachmentContent
                    "ContentType" :  mime_type,    
                    "Size"        :  attachment_file_size, # must be size before encoding!!
                    "User"        :  'user/%s' % self.contextHelper.user_oid,
                   #"Artifact"    :  artifact.ref  # (Artifact is an 'optional' field)
                  }

# While it's actually possible to have an Attachment not linked to an Artifact,
# in most cases, it'll be far more useful to have the linkage to an Artifact than not.
if artifact:  
    attachment_info["Artifact"] = artifact.ref

Thus, the addAttachment method will actually only work for objects that inherit from Artifact, i.e. Stories, Defects, Tasks, TestCases, etc. As seen in WSAPI Docs, to associate an Attachment to a TestCaseResult, the needed attribute is actually "TestCaseResult". This syntax was chosen since a TestCaseResult is actually a WorkspaceDomainObject, and not an Artifact.

unable to get revisions / revesionshistory / changesets for rally artefacts

I observed that apparently there is no way to get all changes made on a rally object.

Now I am parsing them using:

for r in rally.get('User Story', fetch=True, query=""):

Still, the r.Changesets is always an empty list.

I observed that I can obtain Revisions using a similar query but these seem to be Revisions in general, not revisions made to a specific User Story.

I checked the documentation and google a lot but it seems that there is no information regarding how to change the changes made on a specific Story / Defect / ...

Still getting failures with *some* 2014-1 systems

If I use 1.0.1 with WS API 2.0 I get : "IndexError: list index out of range"

If I use 0.9.4 with WS API 1.43 it works on our test system running 2014-1

However on our production system running 0.9.4I get the "StopIteration" exception, which is also running 2014-1

This raises a few questions

  • why isn't it working at all with 1.0.1
  • why is it working on one 2014-1 system and not the other
  • how do I troubleshoot this

Exposing the search api

I wanted to use the search:
slm/webservice/v2.x/search

could figure out how to do it correctly with pyral

anyone have any idea ?

Python REST API doesn't quote % character in queries

pyral version 0.9.4

I'm using a query of the form rally.get('UserStory',fetch=True,query='Name = " -x% degradation in xxx"') and get back the 500 unexpected error page.

I turned on logging and found that, while the spaces in the query string are replaced to %20, the % character itself is untouched, leading to a malformed URL. If I wrap the query argument with a call to urllib.quote everything works.

I stepped through the call using pdb and find that at /usr/local/lib/python2.7/site-packages/pyral/query_builder.py(194)parenGroups() a call to
''.replace() has replaced a call to urllib.quote. Someone has made the deliberate decision at some point to only quote space characters.

Unfortunately, this was done before query_builder.py was uploaded to GitHub, so I can't use version history to determine why this was done. Obviously I can patch to escape % characters, but without understanding the rationale for pyral to only escape spaces in the query argument I can't contribute a better patch.

Can someone with more knowledge of what pyral is trying to do here let me know which characters pyral regards as safe and which should be escaped? I can then produce a general fix and not just a specific fix for my current use case.

Support for Collection objects

In pyral 1.1.1, I don't see any mention of a method to modify many-to-many relationships, such as Project-SCMRepository or Changeset-Artifact. At least it doesn't appear to be documented.

Adding a list of object references in a post() or update() call doesn't seem to have any effect, but the
underlying API does support modifying Collections via the Collection URL for that type. What I was
hoping to find in pyral was an equivalent add() and remove() method. Am I missing something?

platform identifier for use of Cygwin with pyral not present for Pinger operation

The Pinger.PING_COMMAND dict in context.py (line 711) doesn't accommodate use of Cygwin.
Based on a stack trace from a user it appears that they are using the Cygwin python executable rather than a Windows Python installation. The platform.system() method returns a string that begins with 'CYGWIN' when running the Cygwin python. Adjust the code in context.py to accommodate the use of Cygwin python with pyral.

pyral.context.Pinger considered harmful

Before attempting to connect to Rally via HTTP, pyral uses the pyral.context.Pinger class to attempt to ping the server to see if it is reachable. This is problematic for several reasons:

  • It is implemented by calling out to an external "ping" binary, which may or may not be available
    • Some security-conscious administrators are prone to removing the setuid bit from the ping binary, rendering it useless to anyone but root
  • Instead of using the tmpfile module, it writes the output of this call to a file called ".ping-bucket" in the current working directory, which is problematic for a number of reasons
    • This presumes that the current working directory is writable, and fails badly if it isn't
    • If you're running multiple instances of a script that use pyral in parallel, they could end up stomping on each other
    • Predictable temporary file names are a favorite attack vector of malicious individuals
  • It assumes that the host it is running on is able to transmit and receive ICMP ping packets
    • Some admittedly-misguided administrators are prone to filtering all ICMP
    • A host being pingable or not pingable is not a particularly good predictor of being reachable or not reachable via HTTP

I was going to submit a pull request to update Pinger to use tmpfile instead of "./.ping-bucket" but upon further consideration I think it would be better for it to be removed entirely. All it does is introduce several more ways to fail, which may or may not actually have anything to do with the availability of the Rally API. If there are network issues that are preventing you from reaching the API, then the HTTP connection will fail, and you can report the error from that, instead of trying some arbitrary test first.

Pyral: function addAttachment cannot add binary files like pictures

The function addAttachment in restapi.py cannot correctly add picture files: the picture file is attached indeed but with a incorrect content (only 1 kB of data).

Such pictures are not valid data.

The issue come from the way the files are read

with open(filename, 'r') as af:
    contents = base64.b64encode(af.read())

The file should be read as binary open(filename, 'rb')

KeyError: u'Subscription' while trying to obtain Rally object

Hi.

Since today, pyral stopped working. I'm trying to obtain Rally object in a usual way:

`
options = ['--rallyServer=%s' % 'rally1.rallydev.com', '--workspace=%s' % currentUser.getWorkspace(), '--project=%s' % currentUser.getProject()]
options.append('--rallyUser=%s' % 'currentUser.getUser()')
options.append('--rallyPassword=%s' % currentUser.getRlPass())

server, user, password, apikey, workspace, project = rallyWorkset(options)

try:
    if apikey:
        Rally(server, apikey=apikey, workspace=workspace, project=project)
    else:
        Rally(server, user=user, password=password, workspace=workspace, project=project)                
except Exception as e:
    print e

`

and I'm getting an exception:

Traceback (most recent call last): File "/venv/local/lib/python2.7/site-packages/pyral/restapi.py", line 228, in __init__ self.contextHelper.check(self.server) File "/venv/local/lib/python2.7/site-packages/pyral/context.py", line 226, in check processSchemaInfo(self.getWorkspace(), schema_info) File "/venv/local/lib/python2.7/site-packages/pyral/entity.py", line 868, in processSchemaInfo item = SchemaItem(raw_item_info) File "/venv/local/lib/python2.7/site-packages/pyral/entity.py", line 645, in __init__ self.Attributes.append(SchemaItemAttribute(attr)) File "/venv/local/lib/python2.7/site-packages/pyral/entity.py", line 717, in __init__ self.Subscription = attr_info[u'Subscription'] KeyError: u'Subscription'

Reminder: yesterday all was working perfectly. Does that mean that Rally did some API changes?

Exception raise StopIteration at rallyresp.py", line 253,

It seems that instantiations fails with a StopIteration exception.

pyral=(1, 0, 0)
requests=2.3.0
python=2.7.x (osx)

rally = Rally("rally1.rallydev.com", "[email protected]", password) #, workspace=workspace,
Traceback (most recent call last):
  File "./rally.py", line 11, in <module>
    rally = Rally("rally1.rallydev.com", "[email protected]", password) #, workspace=workspace,
  File "/Users/sorins/Library/Python/2.7/lib/python/site-packages/pyral/restapi.py", line 223, in __init__
    self.contextHelper.check(self.server)
  File "/Users/sorins/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 226, in check
    self._getDefaults(response)
  File "/Users/sorins/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 298, in _getDefaults
    proj = projects.next()
  File "/Users/sorins/Library/Python/2.7/lib/python/site-packages/pyral/rallyresp.py", line 253, in next
    raise StopIteration
StopIteration

Missing README.rst file

Having trouble running pip install as well as a basic python setup.py install because the package is missing the README.rst file. I see it in MANIFEST.in so I'm not sure why it's not being included.

This was pyral-1.0.1.tar.gz file.

Support for SSO login

Enterprise customers, like my company which has many thousands of users, have implemented SSO into Rally. It would be really great if Pyral would support this mode of signing in to Rally.
Pyral looks like an awesome way to interact with Rally - I hope this can be addressed soon.
Thank you.

Support for RecycleBinEntry

Currently when I try to use RecycleBinEntry in a query , I get the error: "pyral.entity.InvalidRallyTypeNameError: RecycleBinEntry"

Looking in entity.py, it appears that it is set to never be found. I am assuming that is because it is not supported. Can it get added?

Issue with pyral package (Python Rally Toolkit)

We are able to login using these credentials from the CA Agile Central UI but , we are facing the error mentioned earlier when we are pulling the date with the API.
Temporary fix has been:
temporary fix by commenting out the following lines in the pyral package.

Location of file : /usr/local/lib/python2.7/dist-packages/pyral/entity.py

self.Subscription = attr_info[u'Subscription'] # no longer in rally REST

self.Workspace = attr_info[u'Workspace'] # no longer in rally REST

Here is the error message:
" After initiating the two Python scripts separately in Putty: ‘ python testcase-multiprocessing.py’ python defect_bulk.py
We are getting the following error: KeyError: u'Subscription' on each script run.

It’ s my understanding, that of the 7 scripts we are running only the two following are causing the Subscription error

  1. testcase-multiprocessing.py
  2. defect_bulk.py

Regards,
Thomas

First script error for testcase-multiprocessing.py

root@vm-anushrkr-001:/home/stackstorm# python testcase-multiprocessing.py
Traceback (most recent call last):
File " testcase-multiprocessing.py" , line 20, in < module>
rally = Rally('rally1.rallydev.com', user='[email protected]', password='ermorq2014', workspace='Annuities Business Transformation Workspace',project='Annuities Business Transformation (ABT) Program')
File " /usr/local/lib/python2.7/dist-packages/pyral/restapi.py" , line 228, in init
self.contextHelper.check(self.server)
File " /usr/local/lib/python2.7/dist-packages/pyral/context.py" , line 226, in check
processSchemaInfo(self.getWorkspace(), schema_info)
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 868, in processSchemaInfo
item = SchemaItem(raw_item_info)
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 645, in init
self.Attributes.append(SchemaItemAttribute(attr))
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 717, in init
self.Subscription = attr_info[u'Subscription']
KeyError: u'Subscription'
root@vm-anushrkr-001:/home/stackstorm#

Second script error for defect_bulk.py

root@vm-anushrkr-001:/home/stackstorm# python defect_bulk.py
Traceback (most recent call last):
File " defect_bulk.py" , line 29, in < module>
rally = Rally('rally1.rallydev.com', user='[email protected]', password='ermorq2014', workspace='Annuities Business Transformation Workspace',project='Annuities Business Transformation (ABT) Program')
File " /usr/local/lib/python2.7/dist-packages/pyral/restapi.py" , line 228, in init
self.contextHelper.check(self.server)
File " /usr/local/lib/python2.7/dist-packages/pyral/context.py" , line 226, in check
processSchemaInfo(self.getWorkspace(), schema_info)
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 868, in processSchemaInfo
item = SchemaItem(raw_item_info)
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 645, in init
self.Attributes.append(SchemaItemAttribute(attr))
File " /usr/local/lib/python2.7/dist-packages/pyral/entity.py" , line 717, in init
self.Subscription = attr_info[u'Subscription']
KeyError: u'Subscription'
root@vm-anushrkr-001:/home/stackstorm#
"

Doesn't work with Requests 0.9 or later

The latest version of requests that pyral will work with is 0.8.9; 0.9 turned on SSL verification by default (the only code change between 0.8.9 and 0.9 is the changing of verify=None in Session.__init__'s arguments to verify=True), and this has broken pyral:

H:\Private\pyral-0.8.9>python rallyfire.py
|rally1.rallydev.com| |[email protected]| |G3ronim0!| |default| |default|
Traceback (most recent call last):
  File "H:\Private\pyral-0.8.9\rallyfire.py", line 56, in <module>
    main(sys.argv[1:])
  File "H:\Private\pyral-0.8.9\rallyfire.py", line 26, in main
    rally = Rally(server, user, password, workspace=workspace, project=project)
  File "H:\Private\pyral-0.8.9\pyral\restapi.py", line 165, in __init__
    self.contextHelper.check(self.server)
  File "H:\Private\pyral-0.8.9\pyral\context.py", line 182, in check
    raise RallyRESTAPIError(problem)
pyral.context.RallyRESTAPIError: 404 Target host: 'rally1.rallydev.com' doesn't support the Rally WSAPI

Unable to access item Error

Hello,

When I try the call:

rally = Rally(SERVER, USER, PASSWORD)

I'm getting:

ERROR: Unable to access item 5 (4 items served so far from a container purported to be 361 items in length)
Traceback (most recent call last):
File "./rallyApiTest.py", line 11, in
rally = Rally(SERVER, USER, PASSWORD)
File "/Library/Python/2.7/site-packages/pyral/restapi.py", line 223, in init
self.contextHelper.check(self.server)
File "/Library/Python/2.7/site-packages/pyral/context.py", line 227, in check
self._getWorkspacesAndProjects(workspace=self._defaultWorkspace, project=self._defaultProject)
File "/Library/Python/2.7/site-packages/pyral/context.py", line 638, in _getWorkspacesAndProjects
for project in response:
File "/Library/Python/2.7/site-packages/pyral/rallyresp.py", line 273, in next
raise IndexError("RallyRESTResponse._page[%d]" % self._curIndex)
IndexError: RallyRESTResponse._page[4]

I tried to use the patch in #25 but this gives me:

WARNING: Had to reduce project count from 361 to 12
ERROR: Unable to access item 3 (9 items served so far from a container purported to be 361 items in length)
Traceback (most recent call last):
File "./rallyApiTest.py", line 11, in
rally = Rally(SERVER, USER, PASSWORD)
File "/Library/Python/2.7/site-packages/pyral/restapi.py", line 223, in init
self.contextHelper.check(self.server)
File "/Library/Python/2.7/site-packages/pyral/context.py", line 227, in check
self._getWorkspacesAndProjects(workspace=self._defaultWorkspace, project=self._defaultProject)
File "/Library/Python/2.7/site-packages/pyral/context.py", line 652, in _getWorkspacesAndProjects
for project in response:
File "/Library/Python/2.7/site-packages/pyral/rallyresp.py", line 277, in next
raise IndexError("RallyRESTResponse._page[%d]" % self._curIndex)
IndexError: RallyRESTResponse._page[2]

There has been no change apart from installing a new version of PyRal.

I have rolled back to PyRal 0.9.4 but I'm concerned that version of the API will no longer be functional soon.

HierarchicalRequirement object gives attribute error for Parent, HasParent is True

I retrieve a list of stories using get(...). Fetch is set to a list of fields, not to True. The list of fields contains both 'HasParent' and 'Parent' I get through many stories in the list and the Parent attribute is always available when HasParent is true. Then I hit a story giving AttributeError on Parent when HasParent is true. If I get that story on its own (using FormattedID = "..."') in a query with fetch=True, the Parent attribute is present as expected.
Where should I start to look and what debugging should I turn on so I can give you a real issue report you stand a chance of fixing?

rally.get("User") does retried only current user not all users

response = rally.get("User", fetch=True, query="")

It seems that as opposed to the other similar calls like ones for "Defect", "User Story" this call does return only the current user instead of returning a collection with all users.

I tested and the same user is able to retrieve the list of users using the web interface.

Updating Tag in rally

Hi,
I have been using pyral extensively.
If you query rally for a Test Case's "tags" using pyral's get() API and appropriate query_criteria a list is returned.

My understanding is that this "Tags" list internally has elements which are dictionaries themselves and contain the attribute "Name" which represents the name of the tag.

Hence when you the following:
for testCase in response:
print(testCase.Tags[0].Name) -> you get the appropriate tag name.

pyral's update() is used to update necessary fields.(it takes a dictionary as an argument)
It would be very helpful if you could provide a code snippet depicting how to update a "Tags" name using pyral's update API.

Is anyone working on support for Rally API v2.0?

The 0.9.4 toolkit uses API version 1.43. This will become not supported in June (See the warning from the Rally REST API response: Please update your client to use the latest version of the API. You can find the latest version at https://rally1.rallydev.com/slm/doc/webservice/index.jsp?version=v2.0. API status is Deprecated and will become Not Supported on 2014-06-20)

I tried using the version argument of the Rally object constructor to specify v2.0. and got the following exception:
Traceback (most recent call last):
File "", line 1, in
File "/Users/pknight/local/lib/python2.7/site-packages/pyral/restapi.py", line 218, in init
self.contextHelper.check(self.server)
File "/Users/pknight/local/lib/python2.7/site-packages/pyral/context.py", line 223, in check
self._loadSubscription()
File "/Users/pknight/local/lib/python2.7/site-packages/pyral/context.py", line 236, in _loadSubscription
self._defaultWorkspace = subscription.Workspaces[0]
TypeError: 'Workspace' object does not support indexing

So the v2.0 API returns subscription workspaces differently (just a count and a ref as far as I can see.) I could work on this but don't want to waste time if someone else is already on it.

Support for getting "SchedulableArtifact" to allow getting stories and defects from an iteration

Low priority and more a discussion point at this stage.

I'd like to get all the stories and defects delivered in an iteration in a single list (to reflect priority order.) I can get them as two separate queries (on 'HierarchicalRequirement' and 'Defect'), but because 'SchedulableArtifact' isn't a concrete class, pyral blocks it. The query on 'SchedulableArtifact' works when I test it in the Rally WSAPI page and returns the list I need.

So my question really is, is this too niche to be worth pursuing and I should just run two queries? Given that the result of the query contains the type information, instantiating the correct concrete entities (HierarchicalRequirement or Defect) from the returned JSON is in principle do-able.

What do people think?

422 Could not parse: Unknown operator ")"

When trying to query a defect from Rally, I received this error (in the title).
I managed to do testing and determine the issue.
This is the code: rally.get('Defect', fetch=True, query='Name="value"')

The Behavior as I saw it is this:
Pyral cannot handle queries that have the equal sign next to the name of the field. There has to be a space in between the field name and the equal sign.
Example:
query='Name = "value"' - does not throw the error because there are spaces between Name, the equal sign, and "value"
query='Name="value"' - throws the error because there are no spaces

Please fix or place better responses as this will impact any new users.

Extraneous line in examples/getitem.py causes credentials error

In examples/getitem.py, the line "rally = Rally(server, user, password)" seems to be there in error. It overwrites the first assignment of the variable. I can only get the file to work if I remove it.

    if apikey:
        rally = Rally(server, apikey=apikey, workspace=workspace, project=project)
    else:
        rally = Rally(server, user=username, password=password, workspace=workspace, project=project)

    rally = Rally(server, user, password)      # specify the Rally server and credentials

Getting exception creating Rally object with 1.0.0

I'm trying to create the initial Rally object and I'm getting the following traceback. The same call works fine with 0.9.4. If you let me know what else you need to debug or anything you need me to run that will help, I'll try to get that for you.

rally=Rally(RALLY_SERVER,RALLY_USER,RALLY_PASSWORD,workspace=RALLY_WORKSPACE,project=RALLY_PROJECT)
ERROR: Unable to access item 10 (9 items served so far from a container purported to be 13 items in length)
Traceback (most recent call last):
File "", line 1, in
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/restapi.py", line 223, in init
self.contextHelper.check(self.server)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 226, in check
self._getDefaults(response)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 293, in _getDefaults
projects = self.agent.get('Project', fetch="Name", workspace=self._defaultWorkspace)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/restapi.py", line 786, in get
context, augments = self.contextHelper.identifyContext(**kwargs)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 543, in identifyContext
self._establishContext(kwargs)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 522, in _establishContext
self._getWorkspacesAndProjects(workspace=workspace, project=project)
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/context.py", line 638, in _getWorkspacesAndProjects
for project in response:
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/rallyresp.py", line 271, in next
self._page[:] = self.__retrieveNextPage()
File "/Users/pknight/Library/Python/2.7/lib/python/site-packages/pyral/rallyresp.py", line 327, in __retrieveNextPage
content = json.loads(response.content)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/init.py", line 338, in loads
return _default_decoder.decode(s)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 365, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 383, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

The same call works fine with 0.9.4. What o

Adding a Tag to an entity ?

I wanted to use pyral to add tags to defects
and I couldn't figure out how to do it

info = dict(test_id="ABC", platform="AAA")
tag1 = rally.create('Tag', dict(Name=info['test_id']))
tag2 = rally.create('Tag', dict(Name=info['platform']))

what's next ?

Problems hydrating previously unhydrated PortfolioItem objects

BIG REWORDING AS I THINK MY ORIGINAL REPORT WAS CONFUSINGLY WORDED.

These problems arose when WSAPI 2.0 started requiring the full hierarchical entity type name of portfolio items in the REST API instead of the sub type name (i.e. requiring PortfolioItem/Feature instead of Feature.) This is handled fine in the initial request to get an object, but doesn't work when pyral needs to hydrate a previously unhydrated object. This is because the code to hydrate the object that builds a get request doesn't handle the "/" in the middle of portfolio entity type names.

There are two issues:

  1. In entity.py Persistable.__getattr__ incorrectly extracts portolio item entity names when splitting the self._ref. To construct the entity name to send to the Rally API server it needs to cope with a '/' within entity types ('PortfolioItem/Feature' vs 'HierarchicalRequirement')

This is addressed by first splitting on WS_API_VERSION + '/' to get a string containing just the entity name and oid before further splitting that to extract those fields.

  1. Although the server wants the entity type to be e.g. 'PortfolioItem/Feature' in the request, it uses 'Feature' as the key in the response content. However, the Pyral class for the unhydrated feature object (in this case) is 'PortfolioItem' so we get a KeyError when we try to extract the response content.

This is addressed by catching the KeyError on 'PortfolioItem', then looping through PORTFOLIO_ITEM_SUB_TYPES, re-raising the original exception if we don't find the contents.

Here's a file that shows the problem (if you have access to my workspace and projects - otherwise just put in your own)

import pyral
import metadata


class RallyError(Exception):
    pass


_rally_instance = None


def get_rally_instance():
    global _rally_instance

    if _rally_instance is None:
        _rally_instance = pyral.Rally(
            server=metadata.rally_auth[u"server"],
            user=metadata.rally_auth[u"user"],
            password=metadata.rally_auth[u"password"],
            workspace=metadata.rally_auth[u"workspace"],
            project=metadata.rally_auth[u"project"])

    return _rally_instance

rally = get_rally_instance()

unhydrated = list(rally.get("PortfolioItem/Feature", fetch=False,
                            query='FormattedID = "F226"'))[0]
hydrated = list(rally.get("PortfolioItem/Feature", fetch=True,
                         query='FormattedID = "F226"'))[0]
print hydrated.FormattedID # this works
print unhydrated.FormattedID # this throws an unknown OID 422 exception

Pinger

Pyral does not work for linux. It fails because the pinger class throws an exception:

ping: invalid option -- '1'

Make ping to target_host (proxy) optional

When a proxy server:port is specified in code a check is performed in context.py. Many enterprise level proxy has icmp/ping disabled to avoid DOS. I such cases below code would just crash even in case of legitimate proxy server. It needs better way to check or make ping optional.

146 # @toto: Make this ping optional. It will break if icmp is disabled on the target_host
147 # reachable, problem = Pinger.ping(target_host)
148 # if not reachable:
149 # if not problem:
150 # problem = "host: '%s' non-existent or unreachable" % target_host
151 # raise RallyRESTAPIError(problem)

Download Links on pypi.python.org are incorrect for pyral 1.1.1

Pyral is hosted on pypi as a tgz file, but additional links are made to the github export location from pypi. However these links are incorrect. See:

https://pypi.python.org/simple/pyral/

Look for the link entitled "1.1.1 download_url" This link incorrectly points to:

https://github.com/RallyTools/RallyRestToolkitForPython/blob/master/dists/pyral-1.1.1.zip

Instead of correctly pointing to:

https://github.com/RallyTools/RallyRestToolkitForPython/raw/master/dists/pyral-1.1.1.zip

This causes problems for mirror servers that link to the zip file hosted on github (for example devpi).

For example try running:
pip install -i https://devpi.net/root/pypi pyral==1.1.1

This produces an error that this isn't a zip file since the html that hosts the zip file is not the same as the zip file. This problem also exists for other versions of pyral, but doesn't for all (for example 0.9.2 is correct)

Rally pyral sdk error with a query with more than two terms. (Error parsing expression — expected “)” but saw “AND” instead.)

A valid query string defined by a tuple, fails any time a tuple is used with more than two terms. Here is test code to repro (see http://stackoverflow.com/questions/14675004/rally-pyral-sdk-error-with-a-query-with-more-than-two-terms-error-parsing-expr )

import pyral

rally = pyral.Rally('rally1.rallydev.com', '[email protected]', 'password')

user = rally.getUserInfo(name='User Name').pop(0)
wksp = rally.getWorkspace()
proj = rally.getProject()

print user.FirstName, user.LastName
print wksp.Name
print proj.Name

queryStrings = (
('State != "Closed"', 'Owner = ' + user.ref),
('State != "Fixed"', 'Owner = ' + user.ref),
('State != "Closed"', 'State != "Fixed"'),
('State != "Closed"', 'State != "Fixed"', 'Owner = ' + user.ref),
('State != Closed', 'State != Fixed', 'State != Submitted'),
('State != Fixed', 'ScheduleState != Tested'),
('State != Fixed', 'Owner = ' + user.ref, 'ScheduleState != Tested'),
)

for query in queryStrings:
print "++++++++++++++++++++++++++++++++++++++++++"
print "Query:",query
defects = rally.get("Defect", True, query=query)
print "Number of results:",defects.resultCount
print "Errors:", defects.errors
print
And here is the resulting output

User Name
A Workspace
Web Project
++++++++++++++++++++++++++++++++++++++++++
Query: ('State != "Closed"', u'Owner = user/1234567890')
QUERYJUNK: ((State != "Closed") AND (Owner = user/1234567890))
Number of results: 25
Errors: []

++++++++++++++++++++++++++++++++++++++++++
Query: ('State != "Fixed"', u'Owner = user/1234567890')
QUERYJUNK: ((State != "Fixed") AND (Owner = user/1234567890))
Number of results: 89
Errors: []

++++++++++++++++++++++++++++++++++++++++++
Query: ('State != "Closed"', 'State != "Fixed"')
QUERYJUNK: ((State != "Closed") AND (State != "Fixed"))
Number of results: 149
Errors: []

++++++++++++++++++++++++++++++++++++++++++
Query: ('State != "Closed"', 'State != "Fixed"', u'Owner = user/1234567890')
QUERYJUNK: ((State != "Closed") AND (State != "Fixed") AND (Owner = user/1234567890))
Number of results: 0
Errors: [u'Could not parse: Error parsing expression -- expected ")" but saw "AND" instead.']

++++++++++++++++++++++++++++++++++++++++++
Query: ('State != Closed', 'State != Fixed', 'State != Submitted')
QUERYJUNK: ((State != Closed) AND (State != Fixed) AND (State != Submitted))
Number of results: 0
Errors: [u'Could not parse: Error parsing expression -- expected ")" but saw "AN

[pyral: Python REST API]: Iteration Query with UserIterationCapacities collection fails

Issue:

A query in pyral on Iterations with Fetch=True causes an exception for the UserIterationCapacities collection.

Example:

iteration_query_response = rally.get('Iteration', fetch=True)

Results in the following Exception:

No classFor item for |UserIterationCapacity|
Traceback (most recent call last):
File "get_iterations.py", line 43, in
for iteration in iteration_query_response:
File "/Users/markwilliams/Documents/python-virtualenv/lib/python2.7/site-packages/pyral/rallyresp.py", line 255, in next
entityInstance = self.hydrator.hydrateInstance(item)
File "/Users/markwilliams/Documents/python-virtualenv/lib/python2.7/site-packages/pyral/hydrate.py", line 62, in hydrateInstance
self._setAppropriateAttrValueForType(instance, attrName, attrValue, 1)
File "/Users/markwilliams/Documents/python-virtualenv/lib/python2.7/site-packages/pyral/hydrate.py", line 128, in _setAppropriateAttrValueForType
elements = [self._unravel(element) for element in attrValue]
File "/Users/markwilliams/Documents/python-virtualenv/lib/python2.7/site-packages/pyral/hydrate.py", line 162, in _unravel
return self._basicInstance(thing)
File "/Users/markwilliams/Documents/python-virtualenv/lib/python2.7/site-packages/pyral/hydrate.py", line 110, in _basicInstance
raise KeyError(itemType)
KeyError: u'UserIterationCapacity'

Whereas a query that excludes this collection by specifying explicit field list:

iteration_query_response = rally.get('Iteration', fetch="Name,EndDate,State")

Succeeds.

StopIteration error after Rally Upgrade and switch to LDAP authentication

Hello. I have a few scripts using PyRal that worked fine until the IT department took over management of Rally. The Rally database used did not change, but we moved from On-Premises 2014.1 to 2014.2 and switched to using the Rally LDAP module for authentication. Below is a traceback showing the error. This occurs on both a Mac OS X 10.9 and Red Hat 6 Linux system.

Thank you for your time.

Version Info
pyral.version
(1, 1, 0)

Rally On-Premises 2014.2
Using Rally LDAP module for authentication

Mac OS 10.9.5
Python 2.7.8 (default, Jul 13 2014, 17:11:32)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
py27-requests @2.4.0_0 (via MacPorts)

Red Hat Enterprise Linux Workstation release 6.3 (Santiago)
Python 2.6.6 (r266:84292, Aug 28 2012, 10:55:56)
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux2
requests v2.3.0

Mac OS X traceback
(Note sure why the Mac OS run has the Unverified HTTPS request warning, my script is identical on both machines. I'm thinking it has something to do with the different requests version.)

$ query_rally.py --credentialsFromFile PB9225
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py:730: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.org/en/latest/security.html (This warning will only appear once by default.)
InsecureRequestWarning)
Traceback (most recent call last):
File "./query_rally.py", line 371, in
main(sys.argv[1:])
File "./query_rally.py", line 347, in main
myQueryRally.setRallyObject()
File "./query_rally.py", line 137, in setRallyObject
verify_ssl_cert=self.verify_ssl_cert)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyral/restapi.py", line 227, in init
self.contextHelper.check(self.server)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyral/context.py", line 220, in check
self._getDefaults(response)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyral/context.py", line 259, in _getDefaults
user = response.next()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyral/rallyresp.py", line 256, in next
raise StopIteration
StopIteration

Linux traceback

$ query_rally.py --credentialsFromFile PB9225
Traceback (most recent call last):
File "query_rally.py", line 371, in
main(sys.argv[1:])
File "query_rally.py", line 347, in main
myQueryRally.setRallyObject()
File "query_rally.py", line 137, in setRallyObject
verify_ssl_cert=self.verify_ssl_cert)
File "/ascldap/users/aalorbe/trac/easy_install_files/2.6/site_packages/pyral-1.1.0-py2.6.egg/pyral/restapi.py", line 227, in init
self.contextHelper.check(self.server)
File "/ascldap/users/aalorbe/trac/easy_install_files/2.6/site_packages/pyral-1.1.0-py2.6.egg/pyral/context.py", line 220, in check
self._getDefaults(response)
File "/ascldap/users/aalorbe/trac/easy_install_files/2.6/site_packages/pyral-1.1.0-py2.6.egg/pyral/context.py", line 259, in _getDefaults
user = response.next()
File "/ascldap/users/aalorbe/trac/easy_install_files/2.6/site_packages/pyral-1.1.0-py2.6.egg/pyral/rallyresp.py", line 256, in next
raise StopIteration
StopIteration

Pyral only allows for keying off the workspace by string name

Pyral will only allow you to set your workspace by string name. It does not matter whether you do it when creating a new Rally connection or later with rally.setWorkspace. Because Rally allows you to have multiple workspaces with the same name you would need to key off of the ref to make sure you are hitting the correct workspace.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.