<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
Step1:  Background
This notebook uses the GitHub GraphQL API to report Kubeflow open PRs whcih needs attention according to
Step2:  Distribution of PRs' open time (age)
Step3:  PRs which need attention
A huristic solution is to list prs which have either of the following conditions
Step4:  PRs which need authors' attentions
Step5:  PRs which need editors' attentions
Step6:  PRs whcih have been quiet for over a week
Step7:  PRs whcih have been open for over a mounth
<ASSISTANT_TASK:>
Python Code:
import argparse
import datetime
from dateutil import parser as date_parser
import json
import logging
import numpy as np
import os
import pandas as pd
import pprint
import requests
from pandas.io.json import json_normalize 
query_template={{
  search(query: "org:kubeflow is:pr is:open created:>2019-01-01", type: ISSUE, first: 100, {cursor}) {{
    edges {{
      node {{
        ... on PullRequest {{
          title
                    url
                    number
                    createdAt
                    lastEditedAt
                    updatedAt
                    editor {{
                      login
                    }}
                    author {{
                      login
                    }}
        }}
      }}
     }}
     pageInfo {{
                    endCursor
                    hasNextPage
    }}
      
  }}
}}
headers = {"Authorization": "Bearer {0}".format(os.getenv("GITHUB_TOKEN"))}
search_cursor = None
hasNextPage = True
df = pd.DataFrame()
cursor_text = ""
pageno=0
while hasNextPage:
    print('getting data fo page ',pageno)
    if search_cursor:
          cursor_text = "after:\"{0}\"".format(search_cursor)
    query = query_template.format(cursor=cursor_text)
    request = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers)
    print('request code ',request.status_code)
    rtext=request.text
    rdict=json.loads(rtext)
    prnodes = rdict["data"]["search"]["edges"]
    search_cursor = rdict["data"]["search"]["pageInfo"]["endCursor"]
    hasNextPage = rdict["data"]["search"]["pageInfo"]["hasNextPage"]
    print('nomer of nodes found in this page', len(prnodes))
    rawdf = pd.DataFrame.from_dict(prnodes)[['node']]
    newdf = pd.DataFrame.from_records(rawdf['node'])  #decompose column node to multiple columns
    df  =  pd.concat([df,newdf])
    pageno = pageno +1    
    
     
df['createdAt'] = df['createdAt'].apply(lambda x: pd.Timestamp(x))
df['lastEditedAt'] = df['lastEditedAt'].apply(lambda x: pd.Timestamp(x))
df['updatedAt'] = df['updatedAt'].apply(lambda x: pd.Timestamp(x))
def getTimeDeltaFromNowH(x):
    td = pd.Timestamp.utcnow() - pd.Timestamp(x)
    days, hours, minutes = td.days, td.seconds // 3600, td.seconds % 3600 / 60.0
    return days*24 + hours
    
df['creationAge'] = df['createdAt'].apply(lambda x: getTimeDeltaFromNowH(x))
df['lastEditAge'] = df['lastEditedAt'].apply(lambda x: getTimeDeltaFromNowH(x))
df['updateAge'] = df['updatedAt'].apply(lambda x: getTimeDeltaFromNowH(x))
Explanation: Background
This notebook uses the GitHub GraphQL API to report Kubeflow open PRs whcih needs attention according to:
* The time interval they have been open,
* Last time they have been edited or updated.
It then list the following PRs:
* PRs whcih need autors' attention
* PRs which need editors' attention
* PRs whhch have been quiet for over a week
* PRs whcih have been open for over a mounth
Github Setup
You will need a GitHub personal access token in order to use the GitHub API
* See these instructions for creating a personal access token
* Set the environment variable GITHUB_TOKEN to pass your token to the code
End of explanation
hist = df.hist(column='creationAge', bins=200,figsize=(12,8), color='#86bf91', zorder=2, rwidth=0.9)
ax = hist[0]
for x in ax:
    x.set_xlabel("Age in hours")
    x.set_ylabel("total number of PRs")
Explanation: Distribution of PRs' open time (age)
End of explanation
MAX_AGE = 24*30
MAX_QUIET_TIME = 7*24
needs_attention = df[(df.creationAge > MAX_AGE) |
                     ((df.updateAge > MAX_QUIET_TIME) & (df.lastEditAge > MAX_QUIET_TIME*1.0)) |
                     ((df.updateAge > MAX_QUIET_TIME) &  (df.lastEditAge>df.updateAge*1.0)) |
                     ((df.lastEditAge > MAX_QUIET_TIME*1.0) & (df.lastEditAge < df.updateAge*1.0))
                    ]
needs_attention
Explanation: PRs which need attention
A huristic solution is to list prs which have either of the following conditions:
* No activity is recoreded for the pr for a long time (i.e., both updateAge and lastEditedAge exceeds a threshold).
* Has been open for a long time (i.e., creationAge exceeds a threshold)
* Needs author's attention (i.e. it has been edited for a long time but has not been updated afterwards)
* Needs editor's attention (i.e., it has been updated for a long time but has not been edited afterwards)
End of explanation
needs_attention[(needs_attention.updateAge > MAX_QUIET_TIME) &  (needs_attention.lastEditAge>needs_attention.updateAge*1.0)]
Explanation: PRs which need authors' attentions
End of explanation
needs_attention[(needs_attention.lastEditAge > MAX_QUIET_TIME*1.0) &  (needs_attention.lastEditAge<needs_attention.updateAge*1.0)]
Explanation: PRs which need editors' attentions
End of explanation
needs_attention[(needs_attention.lastEditAge > MAX_QUIET_TIME*1.0) &  (needs_attention.updateAge > MAX_QUIET_TIME)]
Explanation: PRs whcih have been quiet for over a week
End of explanation
needs_attention[needs_attention.creationAge > MAX_AGE]
Explanation: PRs whcih have been open for over a mounth
End of explanation
<END_TASK>