TestCase defined under TestFolder on Rally not getting updated by pyral - python

I'm not able to update the testCase defined on Rally using pyral
Below is the code snippet I am using:
# Get the testcase that needs to be updated
query_criteria = 'FormattedID = "%s"' % tc
rally_response = rally_obj.get('TestCase', fetch=True, query=query_criteria)
target_project = rally.getProject()
testcase_fields = {
"Project" : target_project.ref,
"Workspace" : "workspace/59461540411",
"Name" : "test",
"Method" : "Automated",
"Type" : "Acceptance",
"Notes" : "netsim testing",
"Description" : "description changing",
#"TestCase" : "testcase/360978196712"
}
testcase_response = rally.put('TestCase', testcase_fields)
The status code of the testcase_response is "200" , but the Test Case is not updated.
What is wrong?

You are mixing 2 functions:
rally.put: to create a new WorkItem
rally.update: to modify an existing WorkItem
When you modify an item, you need the reference, FormattedID, or Object ID of the Workitem.
Your code should look like something like that:
# Get the testcase that needs to be updated
import logging
logging.basicConfig(format="%(levelname)s:%(module)s:%(lineno)d:%(msg)s")
def get_test_case(tcid):
"""Retrieve Test Case from its ID, or None if no such TestCase id"""
query_criteria = "FormattedID = %s" % tcid
try:
response = rally_obj.get('TestCase', fetch=True, query=query_criteria)
return response.next()
except StopIteration:
logging.error("Test Case '%s' not found" % tcid)
return None
target_project = rally.getProject()
test_case = get_test_case("TC1234")
if test_case:
testcase_fields = {
"FormattedID" : test_case.FormattedID
"Project" : target_project.ref,
"Workspace" : "workspace/59461540411", # might not be necessary if you don't change it
"Name" : "test",
"Method" : "Automated",
"Type" : "Acceptance",
"Notes" : "netsim testing",
"Description" : "description changed",
}
testcase_response = rally.update('TestCase', testcase_fields)
print(testcase_response)
NOTE: you don't have to have double quotes " in the query.

Related

Finding if a path exists within a json in python

So I am trying to work with an api currently which returns json data such as:
{
"emp1" : {
"EmpName" : "Chris Jackman",
"EmpAge" : "34",
"EmpGender" : "Male",
"EmpDept" : "IT",
"EmpDesg" : "Project Manager"
"EmpSal": {
"2019": 20000
"2020": 23000
},
"emp2" : {
"EmpName" : "Mary Jane",
"EmpAge" : "27",
"EmpGender" : "Female",
"EmpDept" : "IT"
}
}
Occasionally when we query the API one of these fields will be missing. When we try to access it
my_var = my_json["emp2"]["EmpDesg"]
Which will return a key error:
data_dict["EmpDesg"] = my_json["emp2"]["EmpDesg"]
KeyError: 'EmpDesg'
Is there a way to neatly deal with json paths missing rather than wrapping each field in a try catch:
try:
data_dict["EmpName"] = my_json["emp1"]["EmpName"]
except KeyError as e:
data_dict["EmpName"] = ""
try:
data_dict["EmpAge"] = my_json["emp1"]["EmpAge"]
except KeyError as e:
data_dict["EmpAge"] = ""
try:
data_dict["EmpGender"] = my_json["emp1"]["EmpGender"]
except KeyError as e:
data_dict["EmpGender"] = ""
try:
data_dict["salary"] = my_json["emp1"]["EmpSal"]["2020"]
except KeyError as e:
data_dict["salary"] = ""
If you want to check if a key exists, use "key" in data, not a try, except KeyError
Otherwise, if all you want is a default when a key doesn't exist, use .get() with the default parameter
emp1 = my_json["emp1"]
data_dict = {
"EmpName": emp1.get("EmpName", '')
"EmpAge": emp1.get("EmpAge", '')
}
Or
keys = ['EmpName', 'EmpAge']
data_dict = {k: emp1.get(k, '') for k in keys}
To check if a path of arbitrary length exists in a given dict:
def path_exists(d, path) -> bool:
"""Return True if path exists in given dict."""
next = d
while path:
k = path.pop(0)
if k in next:
next = next[k]
else:
return False
return True
For example:
In [4]: path_exists(d, ['emp1', 'EmpName'])
Out[4]: True
In [5]: path_exists(d, ['emp1', 'EmpSal', '2019'])
Out[5]: True
In [6]: path_exists(d, ['emp1', 'EmpSal', '2018'])
Out[6]: False
So you can check whether the path exists (just once) before confidently traversing the dict.

"The document path provided in the update expression is invalid for update" when trying to update a map value

Here is my sample code
import boto3
import os
ENV = "dev"
DB = "http://awsservice.com"
REGION = "us-east-1"
TABLE = "traffic-count"
def main():
os.environ["AWS_PROFILE"] = ENV
client = boto3.resource("dynamodb", endpoint_url=DB, region_name=REGION)
kwargs = {'Key': {'id': 'D-D0000012345-P-1'},
'UpdateExpression': 'ADD #count.#car :delta \n SET #parentKey = :parent_key, #objectKey = :object_key',
'ExpressionAttributeValues': {':delta': 1, ':parent_key': 'District-D0000012345', ':object_key': 'Street-1'},
'ExpressionAttributeNames': {'#car': 'car', '#count': 'count', '#parentKey': 'parentKey', '#objectKey': 'objectKey'}}
client.Table(TABLE).update_item(**kwargs)
if __name__ == "__main__":
main()
What I want to achieve is this:
With a single API call (in this update_item), I want to be able to
If the item does not exit. create an item with a map count and initialise it with {'car': 1} and set the fields parent_key and object_key.
or
If the item already exists, update the field to {'car': 2} (if the original count is 1)
Previously, if I did not use a map, I can successfully update with this expression,
SET #count = if_not_exist(#count, :zero) + :delta,
#parentKey = :parent_key, #objectKey = :object_key
However I am getting this error:
botocore.exceptions.ClientError: An error occurred
(ValidationException) when calling the UpdateItem operation: The
document path provided in the update expression is invalid for update
Which document path is causing the problem? How can I fix it?
For those who landed on this page with similar error:
The document path provided in the update expression is invalid for update
The reason may be:
for the item on which the operation is being performed,
this attribute (count, for example) is not yet set.
Considering the sample code from question,
The exception could be coming from all those items where count is empty or not set. So the update query doesn't know on which map the new value(s) (car, for example) needs to be set or updated.
In the question, it was possible for the OP in the beginning because, the attribute is not a map and the process is simply setting the value to count as is. It's not trying to access a key of an unknown map to set the value.
This can be handled by catching the exception. For example:
from botocore.exceptions import ClientError
...
try:
response = table.update_item(
Key={
"pk": pk
},
UpdateExpression="set count.car = :c,
ExpressionAttributeValues={
':c': "some car"
},
ReturnValues="UPDATED_NEW"
)
except ClientError as e:
if e.response['Error']['Code'] == 'ValidationException':
response = table.update_item(
Key={
"pk": pk
},
UpdateExpression="set count = :count",
ExpressionAttributeValues={
':count': {
':c': "some car"
}
},
ReturnValues="UPDATED_NEW"
)

How to print a value in Python that is inside a Json in MongoDB object

I have this Json, and I need a value from a rate.
"_id" : ObjectId("5addb57d0043582d48ba898a"),
"success" : true,
"timestamp" : 1524477784,
"base" : "EUR",
"date" : "2018-04-23",
"rates" : {
"AED" : 4.492662,
"AFN" : 85.576329,
"ALL" : 128.39508,
"AMD" : 586.837094,
"ANG" : 2.177608,
"AOA" : 267.092358,
"ARS" : 24.678283,
"AUD" : 1.602032,
"AWG" : 2.177639,
"AZN" : 2.079155,
"BAM" : 1.958775,
"BBD" : 2.446786,
"BDT" : 101.517146,
"BGN" : 1.943843,
"BHD" : 0.460968,
"NOK" : 9.626194,
}
And this is my Python code
import pymongo
uri = "mongodb://127.0.0.1:27017"
client = pymongo.MongoClient(uri)
database = client['db']
collection = database['currency']
collection2 = database['countries']
p = str(input('Insert the country: ')).capitalize()
if p=='Norway':
currency = collection.find_one({'NOK'})
print(currency)
I want to print the value inside de NOK, how can I do it?
Thanks in advance.
I think you can call it by :
currency = collection.find_one({"NOK"})
print(currency['rates']['NOK'])
What you're trying to do is fetch a value in a dictionary which is integrated inside of another dictionary. JSON returns are dictionaries.
I imagine that the collection variable contains the JSON return
One way of fetching this data is by calling the dictionary and telling it what key you want the dictionary to return, as the "NOK" key is in the "rates" key we will be calling the rates key first, then when the dictionary has returned the dictionary that contains the "NOK" key we will then pass the "NOK" key to that returned dictionary, so the code looks like this:
currency = collection["rates"]["NOK"]
Another way of doing this is using the for loop, it is a lot longer but may help you understand.
for key in collection:
if key == "rates":
for keyRates in JSON[key]:
if keyRates == "NOK":
currency = JSON[key][keyRates]
Hope this helps

How to Create a PUT request in Python for the following JSON

I have a JSON body like this:
'\n{\n"users" : \n[\n\n{\n"dn" : null,\n"dns_domain" : null,\n"domain" : "UNIX_USERS",\n"email" : null,\n"enabled" : true,\n"expired" : false,\n"expiry" : null,\n"gecos" : "InsightIQ User",\n"generated_gid" : false,\n"generated_uid" : false,\n"generated_upn" : true,\n"gid" : \n{\n"id" : "GID:15",\n"name" : "insightiq",\n"type" : "group"\n},\n"home_directory" : "/ifs/home/insightiq",\n"id" : "insightiq",\n"locked" : false,\n"max_password_age" : null,\n"member_of" : null,\n"name" : "insightiq",\n"object_history" : [],\n"on_disk_group_identity" : \n{\n"id" : "GID:15",\n"name" : "insightiq",\n"type" : "group"\n},\n"on_disk_user_identity" : \n{\n"id" : "UID:15",\n"name" : "insightiq",\n"type" : "user"\n},\n"password_expired" : false,\n"password_expires" : true,\n"password_expiry" : null,\n"password_last_set" : null,\n"primary_group_sid" : \n{\n"id" : "SID:S-1-22-2-15",\n"name" : "insightiq",\n"type" : "group"\n},\n"prompt_password_change" : false,\n"provider" : "lsa-file-provider:System",\n"sam_account_name" : "insightiq",\n"shell" : "/sbin/nologin",\n"sid" : \n{\n"id" : "SID:S-1-22-1-15",\n"name" : "insightiq",\n"type" : "user"\n},\n"type" : "user",\n"uid" : \n{\n"id" : "UID:15",\n"name" : "insightiq",\n"type" : "user"\n},\n"upn" : "insightiq#UNIX_USERS",\n"user_can_change_password" : false\n}\n]\n}\n')
Now I want to create a PUT request in python so as to change the value of "enabled" to false.
This is what I have, but I keep getting a 400 bad request.
def revert_insightIQ_user_account(self):
''' Revert insightIQ_user_account'''
print "Reverting insightIQ user to default... "
req_url = "/platform/1/auth/users/insightiq"
default = {}
default['users'] = []
default['users'].append({})
default["users"][0]["enabled"] = False
self.http_papi.httpPut(self.base_url, self.port, self.username, self.password, req_url, req_body=default)
print "Settings reverted successfully.."
I think I am creating the JSON body format wrongly, because the URL and all is correct (i have double checked that) but I can't figure out what would be the correct one and have reached a dead end. Can someone please help?
edit:
http_papi is a library created which has all the API transactions like GET PUT defined, so whenever I use an API request I call it from that library (it has been imported)
The JSON string source is the URI mentioned : /platform/1/auth/users/insightiq (this along with the cluster IP I am using for my testing)
The JSON string posted is what I get back when I do a raw CURL put request to enable the user. I have to create a same JSON format in my python code and pass enabled = false there.
this worked by just changing the list object "enabled" didn't have to create the DS from scratch.
def revert_insightIQ_user_account(self):
''' Revert insightIQ_user_account'''
print
print "Reverting insightIQ user to default... "
default = {}
req_url = "/platform/1/auth/users/insightiq"
default['enabled'] = False
self.http_papi.httpPut(self.base_url, self.port, self.username, self.password, req_url, req_body=default)
print "Settings reverted successfully..

Replacing strings against template stories in Rally

I can successfully obtain user story information with my Python code; however, I want to replace a specific string located in the details and user story name. For instance, the string could be $projectName and I'd like to replace it with a user inputted value.
Is there something which helps to code for this or is there a working example? I am stuck because this isn't necessarily a file to edit and the Hierarchy output also creates a block for me to develop something that works.
Here is my code for pulling the data:
#!/usr/bin/env python
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, username, password, apikey, workspace, project = rallyWorkset(options)
if apikey:
rally = Rally(server, apikey=apikey, workspace=workspace, project=project)
else:
rally = Rally(server, username=username, password=password, workspace=workspace, project=project)
response = rally.get ('UserStory', fetch=True, query='Name contains "$projecttest"')
for story1 in response:
print story1.details()
Here is the output I get, scrubbed, of course:
HierarchicalRequirement
oid : 81284473268
ref : hierarchicalrequirement/81284473268
ObjectID : 81284473268
ObjectUUID : 67c952b4-e414-4759-a8c5-d7d7543ba98d
_ref : https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/81284473268
_CreatedAt : Dec 14, 2016
_hydrated : True
Name : Robert - test - pyRal - $projecttest
Subscription : <<SCRUBBED>>
Workspace : Workspace.ref (OID SCRUBBED)
FormattedID : US47008
AcceptedDate : None
Attachments : []
Blocked : False
BlockedReason : None
Blocker : None
Changesets : []
Children : []
CreationDate : 2016-12-14T18:21:03.663Z
DefectStatus : NONE
Defects : []
Description : <b>Description</b><div><br /><div>Some format here</div><div><br /></div><div><b>Outcome</b></div><div><b><br /></b></div><div>Some outcome here</div></div>
DirectChildrenCount : 0
Discussion : []
DisplayColor : #21a2e0
DragAndDropRank : O~zbf~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expedite : False
Feature : None
HasParent : False
InProgressDate : None
Iteration : None
LastBuild : None
LastRun : None
LastUpdateDate : 2016-12-19T22:42:48.173Z
LatestDiscussionAgeInMinutes : None
Milestones : []
Notes :
Owner : User.ref (OID SCRUBBED)
Package : None
Parent : None
PassingTestCaseCount : 0
PlanEstimate : None
PortfolioItem : None
Predecessors : []
Project : Project.ref (OID SCRUBBED)
Ready : False
Recycled : False
Release : None
ScheduleState : Ungroomed
ScheduleStatePrefix : U
Successors : []
Tags : []
TaskActualTotal : 0.0
TaskEstimateTotal : 0.0
TaskRemainingTotal : 0.0
TaskStatus : NONE
Tasks : []
TestCaseCount : 0
TestCaseStatus : NONE
TestCases : []
VersionId : 4
__collection_ref_for_RevisionHistory : SCRUBBED
_refObjectUUID : SCRUBBED
AcceptanceCriteria : None
IGNOREAcceptanceCriteria : None
IdeaURL : <pyral.entity.CustomField object at 0x7f1afb79a190>
IdeaVotes : None
JIRAPriority : None
JiraKey : None
JiraLink : None
KanbanState : None
Priority : None
ReleaseNote : None
RequestedDate : None
SNRequest : None
Submitter : None
TestRailPlanID : None
TrackingState : None
=====================================================
So, with PyRal, I would have to send an update to each user story this code pulls, only on the rows which contain the string; however, I would somehow have to store each FormattedID: and the associated Name: field to update, this is where I am stuck, on how to actually store this so it can be iterated over and updated.
You could use template strings which do exactly what you want, using an env-variable like to delimit template tokens:
from string import Template
s = Template('this is $projectName')
s.substitute(projectName='THE_PROJECT')
results in:
'this is THE_PROJECT'
https://docs.python.org/3/library/string.html
Alternate way, if you wrap projectName within curly braces, is using format:
s = 'this is {projectName}'
print(s.format(projectName='THE_PROJECT'))

Categories