<jupyter_start><jupyter_text>Fetch the data from GitHub(Requires an API token)<jupyter_code>api_token = ''

def send_rest_request(url):
    headers = {'Authorization': f'token {api_token}'}
    r = requests.get(url=url, headers=headers)
    r.raise_for_status() # Abort if unsuccessful request
    return r.json()

def send_graphql_request(query, variables):
    headers = {'Authorization': f'token {api_token}'}
    url = 'https://api.github.com/graphql'
    json = {'query':query, 'variables':variables}
    r = requests.post(url=url, json=json, headers=headers)
    r.raise_for_status() # Abort if unsuccessful request
    return r.json()
query = """
query issueDates($cursor: String) {
  repository(owner: "NixOS", name: "nixpkgs") {
    issues(first: 100, after: $cursor) {
      pageInfo {
        endCursor
        hasNextPage
      }
      nodes {
        number
        createdAt
        closedAt
      }
    }
  }
}
"""
fields = ['createdAt', 'closedAt']
issues = pd.DataFrame(columns=fields)
cursor = None
next_page = True
while next_page:
    json = send_graphql_request(query, {'cursor': cursor})
    result = json['data']['repository']['issues']
    next_page = result['pageInfo']['hasNextPage']
    cursor = result['pageInfo']['endCursor']
    for issue in result['nodes']:
        number = issue['number']
        for field in fields:
            issues.loc[number, field] = issue[field]
    sys.stdout.write(f'Current issue: #{number}\r')
    sys.stdout.flush()
issues.to_csv('nixpkgs-issues.csv')<jupyter_output><empty_output><jupyter_text>Analyze the data(can be skipped to directly, by reusing the provided CSV file)<jupyter_code>issues = pd.read_csv('nixpkgs-issues.csv', index_col=0, parse_dates=['createdAt', 'closedAt'])
issues = issues.assign(lifetime=(issues['closedAt'] - issues['createdAt']).apply(
    lambda dt: np.inf if pd.isnull(dt) else dt.total_seconds()
))
lifetime = issues[
    (issues['createdAt'] > pd.to_datetime('2015-01-01T00:00:00Z')) &
    (issues['createdAt'] < pd.to_datetime('2019-01-01T00:00:00Z'))
].groupby(pd.Grouper(key='createdAt', freq="M"))['lifetime'].agg('describe')
# This function computes the mean of all the values it gets until it encounters an infinity
def compute_mean(array):
    total = 0
    number = 0
    for x in array:
        if np.isfinite(x):
            total += x
            number += 1
        else:
            break
    return total / number
for percentile in ['25%', '50%', '75%']:
    plt.plot(lifetime.index, lifetime[percentile], label=f'Time to close {percentile} of the issues created this month')
    percentile_lifetime = compute_mean(lifetime[percentile])
    plt.axhline(y=percentile_lifetime, color='black', lw=0.2, linestyle='--')
    print(f'The average time to close {percentile} of the issues is {pd.to_timedelta(percentile_lifetime, unit="seconds")}')
plt.yscale('log')
plt.legend()
plt.show()<jupyter_output>The average time to close 25% of the issues is 2 days 00:26:37.192708
The average time to close 50% of the issues is 52 days 18:43:55.989583
The average time to close 75% of the issues is 487 days 02:25:32.094827
{'fraction_non_alphanumeric': 0.14111610006414368, 'fraction_numerical': 0.029185375240538807, 'mean_word_length': 3.9904, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '268001', 'license': 'MIT', 'n_tokens_mistral': 1086, 'n_tokens_neox': 1010, 'n_words': 253, 'path': 'nixpkgs-issues.ipynb', 'repo_name': 'Zimmi48/nixpkgs-issues', 'size': '3118'}