<s> from __future__ import print_function <EOL> import argparse <EOL> import datetime <EOL> import dateutil . parser <EOL> import dateutil . tz <EOL> import gzip <EOL> import json <EOL> import logging <EOL> import pickle <EOL> import sys <EOL> from collections import OrderedDict <EOL> from functools import partial <EOL> from itertools import count , groupby <EOL> from six . moves . urllib . request import urlopen <EOL> logging . basicConfig ( level = logging . INFO ) <EOL> API_PARAMS = { <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> IGNORE_ISSUE_TYPE = { <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> } <EOL> LOG_SECTION = OrderedDict ( [ <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ( '<STR_LIT>' , '<STR_LIT>' ) , <EOL> ] ) <EOL> ISSUES_SORT_KEY = lambda issue : ( issue_section_order ( issue ) , int ( issue [ '<STR_LIT>' ] ) ) <EOL> ISSUES_BY_SECTION = lambda issue : issue_section ( issue ) <EOL> def save_object ( filename , obj ) : <EOL> """<STR_LIT>""" <EOL> logging . info ( '<STR_LIT>' . format ( filename ) ) <EOL> try : <EOL> with gzip . GzipFile ( filename , '<STR_LIT:wb>' ) as f : <EOL> f . write ( pickle . dumps ( obj , <NUM_LIT:1> ) ) <EOL> except Exception as e : <EOL> logging . error ( '<STR_LIT>' . format ( e ) ) <EOL> raise <EOL> def load_object ( filename ) : <EOL> """<STR_LIT>""" <EOL> logging . info ( '<STR_LIT>' . format ( filename ) ) <EOL> try : <EOL> with gzip . GzipFile ( filename , '<STR_LIT:rb>' ) as f : <EOL> buf = '<STR_LIT>' <EOL> while True : <EOL> data = f . read ( ) <EOL> if data == '<STR_LIT>' : <EOL> break <EOL> buf += data <EOL> return pickle . loads ( buf ) <EOL> except Exception as e : <EOL> logging . error ( '<STR_LIT>' . format ( e ) ) <EOL> raise <EOL> def issue_section_order ( issue ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> return LOG_SECTION . values ( ) . index ( issue_section ( issue ) ) <EOL> except : <EOL> return - <NUM_LIT:1> <EOL> def issue_completed ( issue ) : <EOL> """<STR_LIT>""" <EOL> labels = issue . get ( '<STR_LIT>' , [ ] ) <EOL> return any ( label [ '<STR_LIT:name>' ] == '<STR_LIT>' for label in labels ) <EOL> def issue_section ( issue ) : <EOL> """<STR_LIT>""" <EOL> labels = issue . get ( '<STR_LIT>' , [ ] ) <EOL> for label in labels : <EOL> if not label [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT>' ) : <EOL> continue <EOL> if label [ '<STR_LIT:name>' ] in LOG_SECTION : <EOL> return LOG_SECTION [ label [ '<STR_LIT:name>' ] ] <EOL> elif label [ '<STR_LIT:name>' ] in IGNORE_ISSUE_TYPE : <EOL> return None <EOL> else : <EOL> logging . warn ( '<STR_LIT>' . format ( label [ '<STR_LIT:name>' ] , issue_line ( issue ) ) ) <EOL> return None <EOL> def issue_tags ( issue ) : <EOL> """<STR_LIT>""" <EOL> labels = issue . get ( '<STR_LIT>' , [ ] ) <EOL> return [ label [ '<STR_LIT:name>' ] . replace ( '<STR_LIT>' , '<STR_LIT>' ) for label in labels if label [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT>' ) ] <EOL> def closed_issue ( issue , after = None ) : <EOL> """<STR_LIT>""" <EOL> if issue [ '<STR_LIT:state>' ] == '<STR_LIT>' : <EOL> if after is None or parse_timestamp ( issue [ '<STR_LIT>' ] ) > after : <EOL> return True <EOL> return False <EOL> def relevent_issue ( issue , after ) : <EOL> """<STR_LIT>""" <EOL> return ( closed_issue ( issue , after ) and <EOL> issue_completed ( issue ) and <EOL> issue_section ( issue ) ) <EOL> def relevant_issues ( issues , after ) : <EOL> """<STR_LIT>""" <EOL> logging . info ( '<STR_LIT>' . format ( after ) ) <EOL> seen = set ( ) <EOL> for issue in issues : <EOL> if relevent_issue ( issue , after ) and issue [ '<STR_LIT:title>' ] not in seen : <EOL> seen . add ( issue [ '<STR_LIT:title>' ] ) <EOL> yield issue <EOL> def closed_issues ( issues , after ) : <EOL> """<STR_LIT>""" <EOL> logging . info ( '<STR_LIT>' . format ( after ) ) <EOL> seen = set ( ) <EOL> for issue in issues : <EOL> if closed_issue ( issue , after ) and issue [ '<STR_LIT:title>' ] not in seen : <EOL> seen . add ( issue [ '<STR_LIT:title>' ] ) <EOL> yield issue <EOL> def all_issues ( issues ) : <EOL> """<STR_LIT>""" <EOL> logging . info ( '<STR_LIT>' ) <EOL> seen = set ( ) <EOL> for issue in issues : <EOL> if issue [ '<STR_LIT:title>' ] not in seen : <EOL> seen . add ( issue [ '<STR_LIT:title>' ] ) <EOL> yield issue <EOL> def get_labels_url ( ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT>' . format ( ** API_PARAMS ) <EOL> def get_issues_url ( page , after ) : <EOL> """<STR_LIT>""" <EOL> template = '<STR_LIT>' <EOL> return template . format ( page = page , after = after . isoformat ( ) , ** API_PARAMS ) <EOL> def get_tags_url ( ) : <EOL> """<STR_LIT>""" <EOL> return '<STR_LIT>' . format ( ** API_PARAMS ) <EOL> def parse_timestamp ( timestamp ) : <EOL> """<STR_LIT>""" <EOL> dt = dateutil . parser . parse ( timestamp ) <EOL> return dt . astimezone ( dateutil . tz . tzutc ( ) ) <EOL> def read_url ( url ) : <EOL> """<STR_LIT>""" <EOL> logging . debug ( '<STR_LIT>' . format ( url = url ) ) <EOL> r = urlopen ( url ) . read ( ) <EOL> return json . loads ( r . decode ( "<STR_LIT>" ) ) <EOL> def query_tags ( ) : <EOL> """<STR_LIT>""" <EOL> return read_url ( get_tags_url ( ) ) <EOL> def query_issues ( page , after ) : <EOL> """<STR_LIT>""" <EOL> return read_url ( get_issues_url ( page , after ) ) <EOL> def query_all_issues ( after ) : <EOL> """<STR_LIT>""" <EOL> page = count ( <NUM_LIT:1> ) <EOL> data = [ ] <EOL> while True : <EOL> page_data = query_issues ( next ( page ) , after ) <EOL> if not page_data : <EOL> break <EOL> data . extend ( page_data ) <EOL> return data <EOL> def dateof ( tag_name , tags ) : <EOL> """<STR_LIT>""" <EOL> for tag in tags : <EOL> if tag [ '<STR_LIT:name>' ] == tag_name : <EOL> commit = read_url ( tag [ '<STR_LIT>' ] [ '<STR_LIT:url>' ] ) <EOL> return parse_timestamp ( commit [ '<STR_LIT>' ] [ '<STR_LIT>' ] [ '<STR_LIT:date>' ] ) <EOL> return None <EOL> def get_data ( query_func , load_data = False , save_data = False ) : <EOL> """<STR_LIT>""" <EOL> if hasattr ( query_func , '<STR_LIT>' ) : <EOL> func_name = query_func . __name__ <EOL> elif hasattr ( query_func , '<STR_LIT>' ) : <EOL> func_name = query_func . func . __name__ <EOL> pickle_file = '<STR_LIT>' . format ( func_name ) <EOL> if load_data : <EOL> data = load_object ( pickle_file ) <EOL> else : <EOL> data = query_func ( ) <EOL> if save_data : <EOL> save_object ( pickle_file , data ) <EOL> return data <EOL> def check_issue ( issue , after ) : <EOL> labels = issue . get ( '<STR_LIT>' , [ ] ) <EOL> if not any ( label [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT>' ) for label in labels ) : <EOL> logging . warn ( '<STR_LIT>' . format ( issue_line ( ( issue ) ) ) ) <EOL> if closed_issue ( issue , after ) : <EOL> if not any ( label [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT>' ) for label in labels ) : <EOL> if not any ( label [ '<STR_LIT:name>' ] in IGNORE_ISSUE_TYPE for label in labels ) : <EOL> logging . warn ( '<STR_LIT>' . format ( issue_line ( ( issue ) ) ) ) <EOL> if '<STR_LIT>' in issue : <EOL> if not any ( label [ '<STR_LIT:name>' ] . startswith ( '<STR_LIT>' ) for label in labels ) : <EOL> logging . warn ( '<STR_LIT>' . format ( issue_line ( issue ) ) ) <EOL> def check_issues ( issues , after = None ) : <EOL> """<STR_LIT>""" <EOL> issues = closed_issues ( issues , after ) if after else all_issues ( issues ) <EOL> issues = sorted ( issues , key = ISSUES_SORT_KEY ) <EOL> for section , issue_group in groupby ( issues , key = ISSUES_BY_SECTION ) : <EOL> for issue in issue_group : <EOL> check_issue ( issue , after ) <EOL> def issue_line ( issue ) : <EOL> """<STR_LIT>""" <EOL> template = '<STR_LIT>' <EOL> tags = issue_tags ( issue ) <EOL> params = { <EOL> '<STR_LIT:title>' : issue [ '<STR_LIT:title>' ] . capitalize ( ) . rstrip ( '<STR_LIT:.>' ) , <EOL> '<STR_LIT>' : issue [ '<STR_LIT>' ] , <EOL> '<STR_LIT>' : '<STR_LIT:U+0020>' . join ( '<STR_LIT>' . format ( tag ) for tag in tags ) + ( '<STR_LIT:U+0020>' if tags else '<STR_LIT>' ) <EOL> } <EOL> return template . format ( ** params ) <EOL> def generate_changelog ( issues , after , heading , rtag = False ) : <EOL> """<STR_LIT>""" <EOL> relevent = relevant_issues ( issues , after ) <EOL> relevent = sorted ( relevent , key = ISSUES_BY_SECTION ) <EOL> def write ( func , endofline = "<STR_LIT>" , append = "<STR_LIT>" ) : <EOL> func ( heading + '<STR_LIT:\n>' + '<STR_LIT:->' * <NUM_LIT:20> + endofline ) <EOL> for section , issue_group in groupby ( relevent , key = ISSUES_BY_SECTION ) : <EOL> func ( '<STR_LIT>' . format ( section ) + endofline ) <EOL> for issue in reversed ( list ( issue_group ) ) : <EOL> func ( '<STR_LIT>' . format ( issue_line ( issue ) ) + endofline ) <EOL> func ( endofline + append ) <EOL> if rtag is not False : <EOL> with open ( "<STR_LIT>" , "<STR_LIT>" ) as f : <EOL> content = f . read ( ) <EOL> f . seek ( <NUM_LIT:0> ) <EOL> write ( f . write , '<STR_LIT:\n>' , content ) <EOL> flines = [ ] <EOL> with open ( "<STR_LIT>" , "<STR_LIT:r>" ) as f : <EOL> flines = f . readlines ( ) <EOL> with open ( "<STR_LIT>" + rtag + "<STR_LIT>" , "<STR_LIT:r>" ) as f : <EOL> starters = ( "<STR_LIT:*>" , "<STR_LIT>" , "<STR_LIT:U+0020>" ) <EOL> flines [ <NUM_LIT:2> : <NUM_LIT:2> ] = [ "<STR_LIT:U+0020>" + line for line in f . readlines ( ) if line . startswith ( starters ) ] <EOL> with open ( "<STR_LIT>" , "<STR_LIT:w>" ) as f : <EOL> f . writelines ( flines ) <EOL> else : <EOL> write ( print ) <EOL> if __name__ == '<STR_LIT:__main__>' : <EOL> parser = argparse . ArgumentParser ( description = '<STR_LIT>' ) <EOL> limit_group = parser . add_mutually_exclusive_group ( required = True ) <EOL> limit_group . add_argument ( '<STR_LIT>' , '<STR_LIT>' , metavar = '<STR_LIT>' , <EOL> help = '<STR_LIT>' ) <EOL> limit_group . add_argument ( '<STR_LIT>' , '<STR_LIT>' , metavar = '<STR_LIT>' , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_argument ( '<STR_LIT:-c>' , '<STR_LIT>' , action = '<STR_LIT:store_true>' , default = False , <EOL> help = '<STR_LIT>' ) <EOL> parser . add_argument ( '<STR_LIT>' , '<STR_LIT>' , metavar = '<STR_LIT>' , <EOL> help = '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> data_group = parser . add_mutually_exclusive_group ( ) <EOL> data_group . add_argument ( '<STR_LIT>' , '<STR_LIT>' , action = '<STR_LIT:store_true>' , default = False , <EOL> help = '<STR_LIT>' ) <EOL> data_group . add_argument ( '<STR_LIT>' , '<STR_LIT>' , action = '<STR_LIT:store_true>' , default = False , <EOL> help = '<STR_LIT>' ) <EOL> args = parser . parse_args ( ) <EOL> if args . since_tag : <EOL> tags = get_data ( query_tags , load_data = args . load_data , save_data = args . save_data ) <EOL> after = dateof ( args . since_tag , tags ) <EOL> heading = '<STR_LIT>' . format ( args . since_tag ) <EOL> elif args . since_date : <EOL> after = dateutil . parser . parse ( args . since_date ) <EOL> after = after . replace ( tzinfo = dateutil . tz . tzlocal ( ) ) <EOL> heading = '<STR_LIT>' . format ( after . date ( ) . isoformat ( ) ) <EOL> issues = get_data ( partial ( query_all_issues , after ) , load_data = args . load_data , save_data = args . save_data ) <EOL> if args . check : <EOL> check_issues ( issues ) <EOL> if args . release_tag : <EOL> heading = '<STR_LIT>' . format ( str ( datetime . date . today ( ) ) , args . release_tag ) <EOL> generate_changelog ( issues , after , heading , args . release_tag ) <EOL> else : <EOL> generate_changelog ( issues , after , heading ) </s>
