Skip to content

Commit

Permalink
Merge pull request #120 from klehman-rally/master
Browse files Browse the repository at this point in the history
custom fields allowedValues retrieval, integration headers handling
  • Loading branch information
klehman-rally committed Apr 9, 2017
2 parents cf3b61f + bc212bf commit 96dff8e
Show file tree
Hide file tree
Showing 41 changed files with 370 additions and 132 deletions.
23 changes: 17 additions & 6 deletions PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Metadata-Version: 1.1
Name: pyral
Version: 1.3.0
Summary: Python toolkit for Rally REST API
Version: 1.3.1
Summary: Python toolkit for Agile Central (Rally) REST API
Home-page: https://github.com/RallyTools/RallyRestToolkitForPython
Author: Kip Lehman (Rally Software Development)
Author: Kip Lehman (CA Technologies, AgileCentral Business Unit)
License: BSD
Download-URL: https://github.com/RallyTools/RallyRestToolkitForPython/raw/master/dists/pyral-1.3.0.zip
Download-URL: https://github.com/RallyTools/RallyRestToolkitForPython/raw/master/dists/pyral-1.3.1.zip
Description: This is the README file for pyral, a package implementing a
Pythonic interface to the Agile Central (formerly Rally) REST API

Expand All @@ -28,18 +28,28 @@ Description: This is the README file for pyral, a package implementing a
The pyral package requires the use of Kenneth Reitz's requests package using version 2.8.0 or better.
As of requests version 2.0.0, there is support for HTTPS over HTTP proxy via the CONNECT request.
The requests package can be found via the Python Package Index site (http://pypi/python.org/index).
The most recent release of pyral (1.3.0) has been tested with requests 2.12.5.
The most recent release of pyral (1.3.1) has been tested with requests 2.12.5.
The six module is also required.


Installation
------------

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 requirements on the six and requests packages, you can use
the setup mechanism.
Once requests and six has been installed, run the setup.py program supplied with
this distribution as::

python setup.py install


Validation
----------

Expand All @@ -63,7 +73,7 @@ Description: This is the README file for pyral, a package implementing a

Keywords: rally,agilecentral,api
Requires: six
Requires: requests>=2.8.1
Requires: requests>=2.10.1
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Expand All @@ -74,5 +84,6 @@ Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries
24 changes: 22 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,20 @@ The git repository is available at https://github.com/RallyTools/RallyRestToolki
Installation
````````````

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 requirements on the six and requests packages, you can use
the setup mechanism.
Obtain the requests_ package and install it according to that package's directions.
As of requests-2.0.0, there is support for HTTPS over HTTP proxy via the CONNECT request.
Use of requests-2.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.3.0) has been tested using requests 2.12.5.
The most recent release of pyral (1.3.1) has been tested using requests 2.12.5.

Obtain and install the six_ module (available from PyPI at https://pypi.python.org/pypi/six)

Expand Down Expand Up @@ -67,7 +76,7 @@ relevant packages.
>> import requests
>> import pyral
>> pyral.__version__
(1, 3, 0)
(1, 3, 1)



Expand Down Expand Up @@ -273,6 +282,17 @@ Prerequisites

Versions
--------
**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.
Expand Down
12 changes: 11 additions & 1 deletion README.short
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,28 @@ Requirements
The pyral package requires the use of Kenneth Reitz's requests package using version 2.8.0 or better.
As of requests version 2.0.0, there is support for HTTPS over HTTP proxy via the CONNECT request.
The requests package can be found via the Python Package Index site (http://pypi/python.org/index).
The most recent release of pyral (1.3.0) has been tested with requests 2.12.5.
The most recent release of pyral (1.3.1) has been tested with requests 2.12.5.
The six module is also required.


Installation
------------

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 requirements on the six and requests packages, you can use
the setup mechanism.
Once requests and six has been installed, run the setup.py program supplied with
this distribution as::

python setup.py install


Validation
----------

Expand Down
19 changes: 19 additions & 0 deletions VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,22 @@
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.3.0 - Apr 2017
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.3.1 - Apr 2017
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.
43 changes: 36 additions & 7 deletions build_dist.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
#############################################################################

import sys, os
import types
import tarfile
import zipfile
import shutil
import re

PACKAGE_NAME = "pyral"
VERSION = "1.3.0"
VERSION = "1.3.1"

AUX_FILES = ['MANIFEST.in',
'PKG-INFO',
Expand Down Expand Up @@ -71,6 +72,7 @@
'test/test_inflation.py',
'test/test_field_access.py',
'test/test_workspaces.py'
'test/test_allowed_values.py',
'test/test_wksprj_setting.py',
'test/test_query.py',
'test/test_big_query.py',
Expand Down Expand Up @@ -103,28 +105,36 @@ def main(args):
reduction_pct = int(reduction_fraction * 100)
print("%-52.52s %6d (%2d%%)" % (info.filename, info.compress_size, reduction_pct))

# got to use Python 2.7 to be able to run python setup.py bdist_wheel
os.system('/usr/local/bin/python setup.py bdist_wheel')
# in order to get a wheel file built, the python used has to have available a setup.py
# that exposes a bdist_wheel method, which in versions of python beyond 2.7, like 3.5., 3.6, etc
# you'll need to have done a 'pip install wheel' which sets up the necessary infrastructure.
os.system('python setup.py bdist_wheel')
wheel_file = "%s-%s-py2.py3-none-any.whl" % (PACKAGE_NAME, VERSION)
# the wheel_file gets written into the dist subdir by default, no need for a copy...

store_packages('dist', [tarball])
store_packages('dists', [tarball, zipped])

doc_dir = 'doc/build/html'
doc_files = [path.split('/')[-1] for path in DOC_FILES if path.startswith(doc_dir)]
webdocs_zip = make_online_docs_zipfile(PACKAGE_NAME, VERSION, doc_dir, doc_files)
webdocs_location = os.path.join(doc_dir, webdocs_zip)
store_packages('dist', [webdocs_location])

################################################################################

def store_packages(subdir, files):
for file in files:
if os.path.exists(file):
shutil.copy(file, '%s/%s' % (subdir, file))
leaf_name = os.path.basename(file)
shutil.copy(file, '%s/%s' % (subdir, leaf_name))
else:
problem = "No such file found: {0} to copy into {1}".format(file, subdir)
sys.stderr.write(problem)

################################################################################

def package_meta(filename):
import imp

if not os.path.exists(filename):
raise Exception('No such file: %s' % filename)
Expand All @@ -136,8 +146,8 @@ def package_meta(filename):
assignments = "\n".join(consties)

#print(assignments)
pkgcfg = imp.new_module('pkgcfg')
exec(assignments, pkgcfg.__dict__)
pkgcfg = types.ModuleType('pkgcfg') # make a new empty module, internally.. no file created
exec(assignments, pkgcfg.__dict__) # now populate the module with our assignments
sys.modules['pkgcfg'] = pkgcfg
return pkgcfg

Expand Down Expand Up @@ -220,6 +230,25 @@ def make_tarball(pkg_name, pkg_version, base_files, example_files, doc_files):

################################################################################

def make_online_docs_zipfile(pkg_name, pkg_version, doc_dir, doc_files):
zf_name = '%s-%s.docs.html.zip' % (pkg_name, pkg_version)
cur_dir = os.getcwd()
os.chdir(doc_dir)
zf = zipfile.ZipFile(zf_name, 'w')
for fn in doc_files:
zf.write(fn, fn, zipfile.ZIP_DEFLATED)
zf.close()

## The following is what has been done before on the command line, when you
## get the recursion opt on the above logic you can drop the os.system call
os.system("zip %s -r %s" % (zf_name, " ".join(doc_files)))
##

os.chdir(cur_dir)
return zf_name

################################################################################

def make_zipfile(pkg_name, pkg_version, base_files, example_files, doc_files):
base_dir = '%s-%s' % (pkg_name, pkg_version)

Expand Down
Binary file added dist/pyral-1.3.0-py2.py3-none-any.whl
Binary file not shown.
Binary file added dist/pyral-1.3.1-py2.py3-none-any.whl
Binary file not shown.
Binary file added dist/pyral-1.3.1.docs.html.zip
Binary file not shown.
Binary file added dist/pyral-1.3.1.tar.gz
Binary file not shown.
Binary file added dists/pyral-1.3.1.tar.gz
Binary file not shown.
Binary file added dists/pyral-1.3.1.zip
Binary file not shown.
Binary file modified doc/build/doctrees/environment.pickle
Binary file not shown.
Binary file modified doc/build/doctrees/index.doctree
Binary file not shown.
Binary file modified doc/build/doctrees/interface.doctree
Binary file not shown.
Binary file modified doc/build/doctrees/overview.doctree
Binary file not shown.
2 changes: 1 addition & 1 deletion doc/build/html/.buildinfo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: b07c03f625d2f2c1cd442854955e285b
config: be043af57ca576920d9be079088a31c7
tags: 645f666f9bcd5a90fca523b33c5a78b7
31 changes: 24 additions & 7 deletions doc/build/html/_sources/interface.txt
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,13 @@ To instantiate a Rally object, you'll need to provide these arguments:
and the default project for the user is not in the workspace specified.
Under those conditions, the project is changed to the first project
(alphabetic ordering) in the list of projects for the specified workspace.
* server_ping (True or False, default in v1.3.0 is False)
* server_ping (True or False, default in v1.3.0 + is False)
Specifies whether a ping attempt will be made to confirm network connectivity
to the Rally server prior to making a Rally WSAPI REST request.
Organizations may have disabled the ability to make ICMP requests so the ping
attempt may fail even though there is network connectivity to the Rally server.
For this reason, the use of the ping=True option is discouraged going forward.
The the ping operation itself will be dropped in the next major release (2.0.0).
The ping operation itself will be dropped in the next major release (2.0.0).
* isolated_workspace (True or False, default in v1.2.0 + is False)
Specifies that the Rally instance will only be used for interacting with
a single workspace (either the user's default workspace or the named workspace).
Expand All @@ -310,6 +310,7 @@ To instantiate a Rally object, you'll need to provide these arguments:
workspaces, using isolated_workspace=False results in a request to AgileCentral
for each workspace, which can result in a noticeable lag before the instantiation
statement returns a ready-for-use Rally instance.
* headers dict with entries for name, vendor, version of software/integration using this package.

If you use an apikey value, any user name and password you provide is not considered, the connection
attempt will only use the apikey.
Expand All @@ -332,7 +333,7 @@ To instantiate a Rally object, you'll need to provide these arguments:

Examples::

rally = Rally('rally1.rallydev.com', 'chester@corral.com', 'bAbYF@cerZ')
rally = Rally('rally1.rallydev.com', 'chester@corral.com', 'bAbYF@cerZ', server_ping=True)

rally = Rally(server='rally1.rallydev.com', user='mchunko', password='mySEk^et')

Expand All @@ -342,7 +343,7 @@ Examples::

rally = Rally(server, apikey="_some-more-numbers", workspace='RockLobster', project='Fence Posts')

rally = Rally('rally1.rallydev.com', 'chester@corral.com', 'bAbYF@cerZ', server_ping=False)
rally = Rally('rally1.rallydev.com', 'chester@corral.com', 'bAbYF@cerZ', headers={'name': 'Fungibles Goods Burn Up/Down', 'vendor': 'Archimedes', 'version': '1.2.3'})



Expand Down Expand Up @@ -377,13 +378,14 @@ Core REST methods and CRUD aliases
- fetch = True/False or "List,Of,Attributes,We,Are,Interested,In"
- query = 'FieldName = "some value"' or ['EstimatedHours = 10', 'MiddleName != "Shamu"', 'Name contains "foogelhorn pop-tarts"', etc.]
- instance = True/False (defaults to False)
- pagesize = n (defaults to 200)
- pagesize = n (defaults to 500)
- start = n (defaults to 1)
- limit = n (defaults to no limit)
- workspace = workspace_name (defaults to current workspace selected)
- project = project_name (defaults to current project selected)
- projectScopeUp = True/False (defaults to False)
- projectScopeDown True/False (defaults to False)
- threads = n (value of 1 insures single-threading, any other value is advisory)

Returns a RallyRESTResponse object that has errors and warnings attributes that
should be checked before any further operations on the object are attempted.
Expand Down Expand Up @@ -475,7 +477,7 @@ Core REST methods and CRUD aliases
keyword arguments:
- projectScopeUp = true/false (defaults to false)
- projectScopeDown = true/false (defaults to false)
- pagesize = n (defaults to 200)
- pagesize = n (defaults to 500)
- start = n (defaults to 1)
- limit = n (defaults to no limit)

Expand Down Expand Up @@ -617,8 +619,23 @@ pyral.Rally instance convenience methods

.. method:: getAllowedValues(entityName, attributeName [,workspace=None])

Given an entityName and and attributeName (assumed to be valid for the entityName)
Given an entityName and and attributeName (which must be valid for the entityName)
issue a request to obtain a list of allowed values for the attribute.
For standard attributes in the set of ('Artifacts', 'Attachments', 'Changesets',
'Children', 'Collaborators', 'Defects', 'DefectSuites', 'Discussion', 'Duplicates',
'Milestones', 'Iteration', 'Release', 'Project', 'Owner', 'SubmittedBy', 'Predecessors',
'Successors', 'Tasks', 'TestCases', 'TestSets', 'Results', 'Steps', 'Tags') this method
will return a [True] value if the entity identified by entityName actually has the
attributeName specified. To get the values associated with the attributes in the
aforementioned list you should use the **get()** method with the entityName as the first
argument and the singular form of the attribute name as the target of the fetch
keyword argument. Of course, this only works with an entity that exists (such as
'Attachment' or 'Milestone' or 'Tag') but not entities named above like 'Discussion',
or 'SubmittedBy' or 'Result'.
For custom fields though there is no such "disqualification", that is the return
value will be either a single value or a list of values regardless of whether the
values are relevant to every such entity type or the values are a list that can vary
per specific instance of the entity type.

.. method:: addAttachment(artifact, filename, mime_type='text/plain')

Expand Down
8 changes: 4 additions & 4 deletions doc/build/html/genindex.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Index &mdash; pyral 1.3.0 documentation</title>
<title>Index &mdash; pyral 1.3.1 documentation</title>



Expand All @@ -34,7 +34,7 @@
<link rel="index" title="Index"
href="#"/>
<link rel="search" title="Search" href="search.html"/>
<link rel="top" title="pyral 1.3.0 documentation" href="index.html"/>
<link rel="top" title="pyral 1.3.1 documentation" href="index.html"/>


<script src="_static/js/modernizr.min.js"></script>
Expand Down Expand Up @@ -63,7 +63,7 @@


<div class="version">
1.3.0
1.3.1
</div>


Expand Down Expand Up @@ -437,7 +437,7 @@ <h2 id="U">U</h2>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'./',
VERSION:'1.3.0',
VERSION:'1.3.1',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true
Expand Down
Loading

0 comments on commit 96dff8e

Please sign in to comment.