Jira Python custom field values and attributes - jira

I have a question.
I work with Jira via Python and there was a need to get the value of the Insight object, which is located in the custom field. For example: Custom Field: Human, customfield_10123.
Objects available for selection in this field:
Alex (name)
А123 (id)
(some attributes)
blonde (hair_color)
1,25 (height)
30 (weight)
I have this code:
issue = jira.issue(issueID)
print(issue.fields.customfield_10123[0])
Result: Alex (A123)
But I want to get some attributes.
issue = jira.issue(issueID)
print(issue.fields.customfield_10123[0].hair_color)
Result what I want: blonde
Perhaps you have any ideas how to do this?

Related

How do i remove rows based on comma-separated list of values in a Power BI parameter in Power Query?

I have a list of data with a title column (among many other columns) and I have a Power BI parameter that has, for example, a value of "a,b,c". What I want to do is loop through the parameter's values and remove any rows that begin with those characters.
For example:
Title
a
b
c
d
Should become
Title
d
This comma separated list could have one value or it could have twenty. I know that I can turn the parameter into a list by using
parameterList = Text.Split(<parameter-name>,",")
but then I am unsure how to continue to use that to filter on. For one value I would just use
#"Filtered Rows" = Table.SelectRows(#"Table", each Text.StartsWith([key], <value-to-filter-on>))
but that only allows one value.
EDIT: I may have worded my original question poorly. The comma separated values in the parameterList can be any number of characters (e.g.: a,abcd,foo,bar) and I want to see if the value in [key] starts with that string of characters.
Try using List.Contains to check whether the starting character is in the parameter list.
each List.Contains(parameterList, Text.Start([key], 1)
Edit: Since you've changed the requirement, try this:
Table.SelectRows(
#"Table",
(C) => not List.AnyTrue(
List.Transform(
parameterList,
each Text.StartsWith(C[key], _)
)
)
)
For each row, this transforms the parameterList into a list of true/false values by checking if the current key starts with each text string in the list. If any are true, then List.AnyTrue returns true and we choose not to select that row.
Since you want to filter out all the values from the parameter, you can use something like:
= Table.SelectRows(#"Changed Type", each List.Contains(Parameter1,Text.Start([Title],1))=false)
Another way to do this would be to create a custom column in the table, which has the first character of title:
= Table.AddColumn(#"Changed Type", "FirstChar", each Text.Start([Title],1))
and then use this field in the filter step:
= Table.SelectRows(#"Added Custom", each List.Contains(Parameter1,[FirstChar])=false)
I tested this with a small sample set and it seems to be running fine. You can test both and see if it helps with the performance. If you are still facing performance issues, it would probably be easier if you can share the pbix file.
This seems to work fairly well:
= List.Select(Source[Title], each Text.Contains(Parameter1,Text.Start(_,1))=false)
Replace Source with the name of your table and Parameter1 with the name of your Parameter.

Can I pull a list of info out of an email?

I get a daily email that lists upcoming appointments, and their length. The number of appointments vary from day to day.
The emails go like this:
================
Today's Schedule
9:30 AM
3h
Brazilian Blowout
[Client #1 name]
12:30 PM
1h
Women's Cut
[Client 2 name]
6:00 PM
45m
Men's Cut
[Client #3 name]
Projected Revenue
===================
I want to create an event in a Google Calendar for each appointment, and it seems like zapier MIGHT be able to do this, but all the help resources I can find are very general in nature.
Is this do-able on Zapier? If so, any nudges in the right direction would be awesome.
Any thoughts greatly appreciated.
I had some time to kill and enjoy the odd challenge. So I have put together a solution that should do what you are looking for. I will break it down by steps.
TEMPLATE
Zapier Trigger - Step 1
Type: Trigger
Module: Gmail
Criteria: User Dependent
Comments: For the trigger zap you will want to use a Gmail specific trigger, something to the effect of "execute trigger on emails titled 'xyz'", or "emails labeled 'xyz'" if you setup a filter in your inbox.
Input screenshot:
Output Screenshot:
Zapier Action - Step 2
Type: Action
Module: Code (Python 3)
Comments: The Code offered by Zapier executes whatever (properly written) code you place in its container. It is especially handy as it allows you to incorporate data from previous steps in it through the use of a dictionary variable titled 'input_data'. Zapier offers the Code module in two languages: Javascript and Python. As I am most familiar with Python my solution for this step was written in Python. I will append the code to the end of this answer. Using the data held in the body of the email (retrieved in step 1) we can execute some string manipulations and datetime conversions to break apart the email into its component parts and pass those on to the following Action Step: Create Calendar Event.
Input Screenshot:
Output Screenshot:
Zapier Action - Step 3
Type: Action
Module: Google Calendar - Create Event
Comments: Using the data outputted from the previous code step we can fill out the required fields for creating a new appointment.
Input Screenshot:
Output Screenshot:
PYTHON CODE
from datetime import timedelta, date, datetime
'''
Goal: Extract individual appointment details from variable length email
Steps:
Remove all extraneous and new line characters.
Isolate each individual appointment and group its relevant details.
Derive appointment start and end times using appointment time and duration.
Return all appointments in a list.
'''
def format_appt_times(appt_dict):
appt_start_str = appt_dict.get("appt_start")
appt_dur_str = appt_dict.get("appt_length")
# isolate hour and minutes from appointment time
appt_s_hour = int(appt_start_str[:appt_start_str.find(":")])
if ("pm" in appt_start_str.lower()):
appt_s_hour = 12 if appt_s_hour + 12 >= 24 else appt_s_hour + 12
appt_s_min = int(appt_start_str[appt_start_str.find(":") + 1 :
appt_start_str.find(":") + 3])
# isolate hour and minutes from duration time
appt_d_hour = 0
appt_d_min = 0
if ("h" in appt_dur_str):
appt_d_hour = int(appt_dur_str[:appt_dur_str.find("h")])
if ("m" in appt_dur_str):
appt_d_min = int(appt_dur_str[appt_dur_str.find("m") - 2 : appt_dur_str.find("m")])
# NOTE: adjust timedelta hours depending on your relation to UTC
# create datetime objects for appointment start and end times
time_zone = timedelta(hours=0)
tdy = date.today() - time_zone
duration = timedelta(hours=appt_d_hour, minutes=appt_d_min)
appt_start_dto = datetime(year=tdy.year,
month=tdy.month,
day=tdy.day,
hour=appt_s_hour,
minute=appt_s_min)
appt_end_dto = appt_start_dto + duration
# return properly formatted datetime as string for use in next step.
return (appt_start_dto.strftime("%Y-%m-%dT%H:%M"),
appt_end_dto.strftime("%Y-%m-%dT%H:%M"))
def partition_list(target, part_size):
for data in range(0, len(target), part_size):
yield target[data : data + part_size]
def main():
# Remove all extraneous and new line characters.
email_body = input_data.get("email_body")
head,delin,*email_body,delin,foot = [text for text in email_body.splitlines() if text != ""]
appointment_list = []
# Isolate each individual appointment and group its relevant details.
for text in partition_list(email_body, 4):
template = {
"appt_start" : text[0],
"appt_end" : None,
"appt_length" : text[1],
"appt_title" : text[2],
"appt_client" : text[3]
}
appointment_list.append(template)
for appt in appointment_list:
appt["appt_start"], appt["appt_end"] = format_appt_times(appt)
return appointment_list
return main()
I am not sure of your familiarity with Python, or programming more generally, but the comments in the code explain what each section is doing. If you have any specific questions regarding aspects of the code let me know. Assuming your email template does not change this setup should work exactly as needed. Let me know if anything is unclear.
UPDATE
I thought it best to address your question in the original answer should anyone else have similar questions.
explaining how this code is removing the extra characters:
There is actually a fair bit going on in the first line, so I will do my best to break it down, and provide resources where necessary.
The code in question:
head,delin,*email_body,delin,foot = [text for text in email_body.splitlines() if text != ""]
First step here was to break the text into manageable chunks. I did so with the line email_body.splitlines() which, by default, breaks strings into a list at each newline character found (you can specify your own delimiter).
If we were to inspect the list at this moment its contents would be something of the following:
["================", "", "Today's Schedule", "", "9:30 AM", "", "3h", ..., "[Client #3 name]", "", "Projected Revenue", "", "==================="]
You will notice there is a fair amount of information in there that we really don't want.
First lets look at the "" elements. These are left over as a result of the blank lines between each line of text, which even though they are blank do still have newline characters at the end of them. There a number of ways you could address this within python. We could simply write a for-loop to go through and copy all elements that are not "" to a new list.
To me this felt like additional work, and besides, Python offers list comprehension for just such a scenario. I won't go too deep into list comprehension as there is a lot that can be said about it, and in more insightful ways than I could muster, but it essentially allows you to provide logic against a set of 'data' to form a list. In this case, I specifically wanted to filter out the "" elements returned from the call to splitlines().
And so you will see I address this with the following line
[text for text in email_body.splitlines() if text != ""]
With that we have a list as above less the "" elements. Now we must turn our attention towards the more 'dynamic' garbage strings. Again there are a number of ways to do this. A, not particularly flexible, option could be to simply store the strings we want to remove in variables something to the effect of:
garb_1 = "==================="
garb_2 = "Projected Revenue"
garb_3 = ...
and once again filter the list with yet another for-loop. I instead chose to leverage Python's list unpacking idiom. Which allows us to 'unpack' list objects (and I believe tuples) into variables. As an example:
one, two, three = ["a", "b", "c"]
I'm sure you can guess what is happening above, as long as we provide the same number of variables as are in the list we can 'unpack' it in this fashion. But wait! In our case we don't know how long the list is going to be as it is entirely dependent on the number of appointments you have for any given day. Well this is where star unpacking enters to elevate the functionality. Using my code as the example:
head,delin,*email_body,delin,foot = [text for text in email_body.splitlines() if text != ""]
The *, in plain-English, is saying "I don't know how many elements to expect just give me all of them in a list". As we know that there will always be two lines of garbage at the beginning and end of the email we can assign them to throw away variables and capture everything in between using our variable length *email_body container.
With all of this complete we now have a list with only the data we are looking to capture. If, as you say, there are additional lines of garbage before or after the email_body, you can simply add additional throw away variables to account for them.
Once again feel free to ask any follow up questions.
Michael
Resources
List Comprehension
Star Unpacking

rails - count records by value

I am trying to group records based on a value from a column, so I can use it to display the information elsewhere. At the moment I have this working if I specify the values in the column -
#city_count = People.select('city,count(*)').where("city in ('london', 'paris')").group(:city).count
This works fine if I want a list of people in London and Paris but if the city list also has Sydney, New York, Rio etc I don't want to keep adding the extra cities to the 'city in', I would like this to just find the people selected by each city.
Does anyone know the best way of doing this? Also if it can include NULL values as well.
Just use:
#city_count = People.group(:city).count
to get counts for all cities. This will include an entry for nil.
A more efficient way would be to use the distinct and count methods together.
#city_counts = Person.distinct.count(:city)
That way the work is done in the db instead of in Ruby.

Sorting on nullable fields in GORM

I'm trying to figure out how to sort on multiple fields in Grails 3, one of which may or may not be null. I have this Book domain:
class Book {
String title
String sortTitle
static constraints = {
title blank: false
sortTitle nullable: true
}
}
Books with titles like "The Peripheral" have a sortTitle of "Peripheral, The", otherwise sortTitle will be null. I want books sorted by sortTitle if one exists, otherwise by title.
I found other similar SO questions, but none with a nullable field. Does anyone happen to have some pointers in the right direction?
You can use:
coalesce(book.sortTitle, book.title)
Here you have the official Hibernate documentation.
I'm not 100% sure on this but it seems to me that sorting by coalesce would lead to the database doing a file sort which could be rather expensive rather than being able to make use of an index.
My suggestion would be to always populate sortTitle with the name you want to sort by and then just use that.
I couldn't quite figure out how to do it purely with GORM, but some raw HQL worked:
def books = Book.findAll("from Book as b order by coalesce(b.sortTitle, b.title)")

Comparing strings with objects in c#/XNA

I have an XML file which is split up using pipes "|". I have some code in a question class that splits up the XML files "Items" as so..
List<string> questionComponents = newquestionString.Split('|').ToList<string>();
questionString = questionComponents[0];
apple = questionComponents[1];
pear = questionComponents[2];
orange = questionComponents[3];
correctAnswer = Int32.Parse(questionComponents[4]);
I want to compare these components with objects which are instantiated in my Game1 class (three fruit - apple, pear, orange). So how do I do this?
A friend helped me get this far. I have no idea how to do this, and after searching google with no luck I've resulted in asking here to you lovely people.
Thanks in advance :D
EDIT: To clear things up...
I have three objects called apple, pear and orange and I want to associate these objects with the strings which are shown in the XML file for each component of the strings. The question string displays a question, [1] answer 1, [2] answer 2, [3] answer [3].
And then I need a way to compare the answer to the object that is eaten in the game..
Assuming you have some kind of Orange object, some kind of Pear object, and some kind of Apple object, in each class override the ToString method.
If you have some generic Fruit or Answer object, consider passing a string in the constructor and returning that string in the ToString method.
EDIT: Since you've now clarified, I would go with Jonathan's idea of having a Name or Answer property; then you can do:
if(object.Answer == questionComponent)
//do stuff
And ToString does not turn the object into a string. It simply returns a user-defined (if you choose to override) string for the object - for the Ints it is "42", and for bools it is "true" or "false". No conversion occurs.
Based on your edit, it sounds like all you're trying to do is be able to look up some concrete object based on a string that you get from a data file? Couldn't you use a Dictionary for this, as in:
Fruit apple = new Apple();
Fruit orange = new Orange();
Dictionary<string,Fruit> map = new Dictionary<string,Fruit>();
map["apple"] = apple;
map["orange"] = orange;
and then later you can get the user's answer/input:
string input = ...
Fruit result;
if(map.TryGetValue(input, out result)) {
// `fruit` now holds the fruit object the user selected.
} else {
// User input did not correspond to a known fruit.
}
But I'm still not convinced I'm understanding your question properly.
It looks like the range of possible strings is limited, so why not just use identifiers in the form of Enums, which you can parse from the string, and set that identifier into the answers and the fruits?
public enum AnswerType
{
Apple,
Pear,
Banana
}
Store the answers in a dictionary mapping ids to answers (casting enum to int for the key), plus the correct answer's id, and now you can know which answer was picked each time, checking the eaten fruit's id, and if the answer was right.

Resources