Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import sys 

2import os 

3import pprint 

4import inspect 

5from logging import getLogger, DEBUG, INFO, WARN, captureWarnings 

6from logging import FileHandler, StreamHandler, Formatter 

7 

8import json 

9import yaml 

10import click 

11import jsonschema 

12from .version import VERSION 

13from .drivers import Base, Phantom, Chrome, Firefox, Safari, Edge 

14from .drivers import WebKitGTK, Dummy, Ie, Opera, Android, Remote 

15 

16drvmap = { 

17 "phantom": Phantom, 

18 "phantomjs": Phantom, 

19 "chrome": Chrome, 

20 "firefox": Firefox, 

21 "safari": Safari, 

22 "edge": Edge, 

23 "webkit": WebKitGTK, 

24 "dummy": Dummy, 

25 "ie": Ie, 

26 "opera": Opera, 

27 "android": Android, 

28 "remote": Remote, 

29} 

30 

31 

32@click.group(invoke_without_command=True) 

33@click.pass_context 

34@click.version_option(version=VERSION, prog_name="selenible") 

35@click.option("--verbose", is_flag=True) 

36@click.option("--quiet", is_flag=True) 

37@click.option("--logfile", type=click.Path()) 

38def cli(ctx, verbose, quiet, logfile): 

39 logfmt = "%(asctime)s %(levelname)s %(name)s %(message)s" 

40 fmt = Formatter(fmt=logfmt) 

41 lg = getLogger() 

42 if verbose: 

43 lg.setLevel(DEBUG) 

44 elif quiet: 

45 lg.setLevel(WARN) 

46 else: 

47 lg.setLevel(INFO) 

48 if logfile is not None: 

49 newhdl = FileHandler(logfile) 

50 newhdl.setFormatter(fmt) 

51 lg.addHandler(newhdl) 

52 else: 

53 newhdl = StreamHandler() 

54 newhdl.setFormatter(fmt) 

55 lg.addHandler(newhdl) 

56 if ctx.invoked_subcommand is None: 

57 print(ctx.get_help()) 

58 

59 

60def loadmodules(driver, extension): 

61 def_modules = ["ctrl", "browser", "content", "imageproc"] 

62 for i in def_modules: 

63 Base.load_modules(i) 

64 for ext in extension: 

65 Base.load_modules(ext) 

66 drvcls = drvmap.get(driver, Phantom) 

67 drvcls.load_modules(drvcls.__name__.lower()) 

68 for ext in extension: 

69 drvcls.load_modules(ext) 

70 return drvcls 

71 

72 

73@cli.command(help="run playbook") 

74@click.option("--driver", default="phantom", type=click.Choice(drvmap.keys())) 

75@click.option("--extension", "-x", multiple=True) 

76@click.option("--step", is_flag=True, default=False) 

77@click.option("--screenshot", is_flag=True, default=False) 

78@click.option("-e", multiple=True) 

79@click.option("--var", type=click.File('r'), required=False) 

80@click.argument("input", type=click.File('r'), required=False) 

81def run(input, driver, step, screenshot, var, e, extension): 

82 captureWarnings(True) 

83 drvcls = loadmodules(driver, extension) 

84 if input is not None: 

85 prog = yaml.safe_load(input) 

86 b = drvcls() 

87 b.variables["driver"] = driver 

88 for k, v in os.environ.items(): 

89 b.variables[k] = v 

90 if var is not None: 

91 b.load_vars(var) 

92 for x in e: 

93 if x.find("=") == -1: 

94 b.variables[k] = True 

95 else: 

96 k, v = x.split("=", 1) 

97 try: 

98 b.variables[k] = json.loads(v) 

99 except Exception: 

100 b.variables[k] = v 

101 b.step = step 

102 b.save_every = screenshot 

103 b.run(prog) 

104 else: 

105 click.echo("show usage: --help") 

106 

107 

108@cli.command("list-modules", help="list modules") 

109@click.option("--driver", default="phantom", type=click.Choice(drvmap.keys())) 

110@click.option("--extension", "-x", multiple=True) 

111@click.option("--pattern", default=None) 

112def list_modules(driver, extension, pattern): 

113 drvcls = loadmodules(driver, extension) 

114 from texttable import Texttable 

115 table = Texttable() 

116 table.set_cols_align(["l", "l"]) 

117 # table.set_deco(Texttable.HEADER) 

118 table.header(["Module", "Description"]) 

119 mods = drvcls.listmodule() 

120 for k in sorted(mods.keys()): 

121 if pattern is not None and k.find(pattern) == -1: 

122 continue 

123 table.add_row([k, mods[k]]) 

124 print(table.draw()) 

125 

126 

127@cli.command("dump-schema", help="dump json schema") 

128@click.option("--driver", default="phantom", type=click.Choice(drvmap.keys())) 

129@click.option("--extension", "-x", multiple=True) 

130@click.option("--format", default="yaml", type=click.Choice(["yaml", "json", "python", "pprint"])) 

131def dump_schema(driver, extension, format): 

132 drvcls = loadmodules(driver, extension) 

133 if format == "yaml": 

134 yaml.dump(drvcls.schema, sys.stdout, default_flow_style=False) 

135 elif format == "json": 

136 json.dump(drvcls.schema, fp=sys.stdout, ensure_ascii=False) 

137 elif format == "python": 

138 print(drvcls.schema) 

139 elif format == "pprint": 

140 pprint.pprint(drvcls.schema) 

141 else: 

142 raise Exception("unknown format: %s" % (format)) 

143 

144 

145@cli.command(help="validate by json schema") 

146@click.option("--driver", default="phantom", type=click.Choice(drvmap.keys())) 

147@click.option("--extension", "-x", multiple=True) 

148@click.argument("input", type=click.File('r'), required=False) 

149def validate(driver, extension, input): 

150 drvcls = loadmodules(driver, extension) 

151 prog = yaml.safe_load(input) 

152 try: 

153 click.echo("validating...", nl=False) 

154 jsonschema.validate(prog, drvcls.schema) 

155 click.echo("OK") 

156 sys.exit(0) 

157 except jsonschema.exceptions.ValidationError as e: 

158 click.echo("failed") 

159 click.echo(e) 

160 sys.exit(1) 

161 

162 

163@cli.command("browser-options", help="show browser options") 

164@click.option("--driver", default="phantom", type=click.Choice(drvmap.keys())) 

165@click.option("--mode", default="example", type=click.Choice(["example", "doc"])) 

166def browser_options(driver, mode): 

167 drvcls = loadmodules(driver, []) 

168 drv = drvcls() 

169 if mode == "doc": 

170 print(inspect.getdoc(drv.driver.__init__)) 

171 return 

172 opts = drv.get_options() 

173 sig = inspect.signature(drv.driver.__init__) 

174 res = {} 

175 for k, v in sig.parameters.items(): 

176 res[k] = v.default 

177 if opts != {}: 

178 res["options"] = {} 

179 for f in dir(opts): 

180 if f.startswith("__") or f.endswith("__"): 

181 continue 

182 if callable(getattr(opts, f)): 

183 s2 = inspect.signature(getattr(opts, f)) 

184 res["options"][f] = [str(x) for x in s2.parameters.values()] 

185 yaml.dump({"browser_setting": res}, sys.stdout, default_flow_style=False) 

186 

187 

188if __name__ == "__main__": 

189 cli()