Coverage for src/fjc_biographies/__main__.py: 100%

28 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-22 22:47 +0000

1"""Command line interface for downloading and exporting the FJC's biographies. 

2 

3Examples: 

4 python -m fjc_biographies 

5 fjc-biographies --update 

6 fjc-biographies --rulebook my_careers.csv 

7 fjc-biographies --jcs --martin-quinn 

8 fjc-biographies --martin-quinn ~/Downloads/justices.csv 

9 fjc-biographies --download-only --data-folder ~/data/fjc 

10 

11""" 

12 

13from __future__ import annotations 

14 

15import argparse 

16import logging 

17import time 

18from collections.abc import Sequence 

19 

20from . import downloader 

21from . import main as biographies 

22 

23logger = logging.getLogger(__name__) 

24 

25 

26def main(arguments: Sequence[str] | None = None) -> None: 

27 """Downloads and exports the FJC's files as the command line arguments say. 

28 

29 Args: 

30 arguments: the command line arguments. Defaults to None, in which case 

31 the arguments passed to the program are used. 

32 

33 """ 

34 parsed = _get_parser().parse_args(arguments) 

35 logging.basicConfig(level = logging.INFO, format = '%(message)s') 

36 started = time.time() 

37 if parsed.download_only: 

38 files = downloader.download( 

39 folder = parsed.data_folder, overwrite = parsed.update) 

40 logger.info( 

41 'Downloaded %s files in %.0fs.', len(files), time.time() - started) 

42 return 

43 files = biographies.run( 

44 parsed.data_folder, update = parsed.update, rulebook = parsed.rulebook, 

45 jcs = parsed.jcs, martin_quinn = parsed.martin_quinn, 

46 scores_folder = parsed.scores_folder) 

47 logger.info( 

48 'Exported %s tables to %s in %.0fs.', 

49 len(files), next(iter(files.values())).parent, time.time() - started) 

50 

51 

52def _get_parser() -> argparse.ArgumentParser: 

53 """Returns the parser for the command line arguments. 

54 

55 Returns: 

56 The command line parser. 

57 

58 """ 

59 parser = argparse.ArgumentParser( 

60 prog = 'fjc-biographies', 

61 description = ( 

62 "Download the FJC's Biographical Directory of Article III Federal " 

63 'Judges and export tidy CSV files and a roster of judges, by ' 

64 'appointment and by judge.')) 

65 parser.add_argument( 

66 '--data-folder', 

67 default = None, 

68 help = ( 

69 'the folder for the downloaded and exported files (default: ' 

70 f'{downloader.data_folder()})')) 

71 parser.add_argument( 

72 '--update', 

73 action = 'store_true', 

74 help = ( 

75 'download the files again even if they were downloaded before, ' 

76 'to get the judges and corrections the FJC has added since')) 

77 parser.add_argument( 

78 '--rulebook', 

79 default = 'judges', 

80 help = ( 

81 "a CSV file of rules that make the roster's fields from judges' " 

82 'careers, or the name of a built-in rulebook (default: ' 

83 '%(default)s)')) 

84 parser.add_argument( 

85 '--jcs', 

86 action = 'store_true', 

87 help = ( 

88 "add each appointment's Judicial Common Space score, computed by " 

89 'the judicial-common-space package')) 

90 parser.add_argument( 

91 '--martin-quinn', 

92 nargs = '?', 

93 const = True, 

94 default = False, 

95 metavar = 'PATH', 

96 help = ( 

97 "add the justices' Martin-Quinn scores and export their scores in " 

98 'each term, downloading them, or from PATH (a "justices.csv" saved ' 

99 'from https://mqscores.wustl.edu/measures.php)')) 

100 parser.add_argument( 

101 '--scores-folder', 

102 default = None, 

103 help = ( 

104 'the folder for the files that the scores come from (default: ' 

105 "the judicial-common-space package's data folder)")) 

106 parser.add_argument( 

107 '--download-only', 

108 action = 'store_true', 

109 help = 'download the files without exporting them') 

110 return parser 

111 

112 

113if __name__ == '__main__': 

114 main()