def _spawn_posix(args: List[str], process_context: ProcessContext) -> None: """ Perform a double fork procedure* to detach from the parent process so that we don't block the user even if their original command's execution is done but the release fetcher is not. [1]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html#tag_11_01_03 """ from httpie.core import main try: pid = os.fork() if pid > 0: return except OSError: os._exit(1) os.setsid() try: pid = os.fork() if pid > 0: os._exit(0) except OSError: os._exit(1) # Close all standard inputs/outputs sys.stdin.close() sys.stdout.close() sys.stderr.close() if platform.system() == 'Darwin': # Double-fork is not reliable on MacOS, so we'll use a subprocess # to ensure the task is isolated properly. process = _start_process(args, env=process_context) # Unlike windows, since we already completed the fork procedure # we can simply join the process and wait for it. process.communicate() else: os.environ.update(process_context) with suppress(BaseException): main(['http'] + args) os._exit(0)
def main(): try: from httpie.core import main exit_status = main() except KeyboardInterrupt: from httpie.status import ExitStatus exit_status = ExitStatus.ERROR_CTRL_C sys.exit(exit_status.value)
def http(*args, **kwargs): """ Invoke `httpie.core.main()` with `args` and `kwargs`, and return a unicode response. """ if 'env' not in kwargs: # Ensure that we have terminal by default (needed for Travis). kwargs['env'] = Environment( colors=0, stdin_isatty=True, stdout_isatty=True, ) stdout = kwargs['env'].stdout = tempfile.TemporaryFile('w+b') stderr = kwargs['env'].stderr = tempfile.TemporaryFile('w+t') try: exit_status = main(args=['--debug'] + list(args), **kwargs) except (Exception, SystemExit) as e: sys.stderr.write(stderr.read()) raise else: stdout.seek(0) stderr.seek(0) output = stdout.read() try: #noinspection PyArgumentList r = StrResponse(output.decode('utf8')) except UnicodeDecodeError: #noinspection PyArgumentList r = BytesResponse(output) else: if TERMINAL_COLOR_PRESENCE_CHECK not in r: # De-serialize JSON body if possible. if r.strip().startswith('{'): #noinspection PyTypeChecker r.json = json.loads(r) elif r.count('Content-Type:') == 1 and 'application/json' in r: try: j = r.strip()[r.strip().rindex('\n\n'):] except ValueError: pass else: try: r.json = json.loads(j) except ValueError: pass r.stderr = stderr.read() r.exit_status = exit_status return r finally: stdout.close() stderr.close()
def test_timeout(get_response): def error(msg, *args, **kwargs): global error_msg error_msg = msg % args exc = Timeout('Request timed out') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) assert ret == ExitStatus.ERROR_TIMEOUT assert error_msg == 'Request timed out (30s).'
def test_error(get_response): def error(msg, *args, **kwargs): global error_msg error_msg = msg % args exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) assert ret == ExitStatus.ERROR assert error_msg == ('ConnectionError: ' 'Connection aborted while doing GET request to URL: ' 'http://www.google.com')
def test_error(get_response): def error(msg, *args, **kwargs): global error_msg error_msg = msg % args exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc ret = main(['--ignore-stdin', 'www.google.com'], custom_log_error=error) assert ret == ExitStatus.ERROR assert error_msg == ( 'ConnectionError: ' 'Connection aborted while doing GET request to URL: ' 'http://www.google.com')
def http(*args, **kwargs): """ Invoke `httpie.core.main()` with `args` and `kwargs`, and return a unicode response. """ if 'env' not in kwargs: # Ensure that we have terminal by default (needed for Travis). kwargs['env'] = Environment( colors=0, stdin_isatty=True, stdout_isatty=True, ) stdout = kwargs['env'].stdout = tempfile.TemporaryFile() stderr = kwargs['env'].stderr = tempfile.TemporaryFile() exit_status = main(args=['--traceback'] + list(args), **kwargs) stdout.seek(0) stderr.seek(0) r = Response(stdout.read().decode('utf8')) r.stderr = stderr.read().decode('utf8') r.exit_status = exit_status stdout.close() stderr.close() if TERMINAL_COLOR_PRESENCE_CHECK not in r: # De-serialize JSON body if possible. if r.strip().startswith('{'): r.json = json.loads(r) elif r.count('Content-Type:') == 1 and 'application/json' in r: try: j = r.strip()[r.strip().rindex('\n\n'):] except ValueError: pass else: r.strip().index('\n') r.json = json.loads(j) return r
def http(*args, **kwargs): # noinspection PyUnresolvedReferences """ Run HTTPie and capture stderr/out and exit status. Invoke `httpie.core.main()` with `args` and `kwargs`, and return a `CLIResponse` subclass instance. The return value is either a `StrCLIResponse`, or `BytesCLIResponse` if unable to decode the output. The response has the following attributes: `stdout` is represented by the instance itself (print r) `stderr`: text written to stderr `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated. If you pass ``error_exit_ok=True``, then error exit statuses won't result into an exception. Example: $ http --auth=user:password GET httpbin.org/basic-auth/user/password >>> httpbin = getfixture('httpbin') >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') >>> type(r) == StrCLIResponse True >>> r.exit_status 0 >>> r.stderr '' >>> 'HTTP/1.1 200 OK' in r True >>> r.json == {'authenticated': True, 'user': '******'} True """ error_exit_ok = kwargs.pop('error_exit_ok', False) env = kwargs.get('env') if not env: env = kwargs['env'] = TestEnvironment() stdout = env.stdout stderr = env.stderr args = list(args) args_with_config_defaults = args + env.config.default_options add_to_args = [] if '--debug' not in args_with_config_defaults: if not error_exit_ok and '--traceback' not in args_with_config_defaults: add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') args = add_to_args + args def dump_stderr(): stderr.seek(0) sys.stderr.write(stderr.read()) try: try: exit_status = main(args=args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) except SystemExit: if error_exit_ok: exit_status = ExitStatus.ERROR else: dump_stderr() raise except Exception: stderr.seek(0) sys.stderr.write(stderr.read()) raise else: if not error_exit_ok and exit_status != ExitStatus.OK: dump_stderr() raise ExitStatusError( 'httpie.core.main() unexpectedly returned' ' a non-zero exit status: {0} ({1})'.format( exit_status, EXIT_STATUS_LABELS[exit_status] ) ) stdout.seek(0) stderr.seek(0) output = stdout.read() try: output = output.decode('utf8') except UnicodeDecodeError: # noinspection PyArgumentList r = BytesCLIResponse(output) else: # noinspection PyArgumentList r = StrCLIResponse(output) r.stderr = stderr.read() r.exit_status = exit_status if r.exit_status != ExitStatus.OK: sys.stderr.write(r.stderr) return r finally: stdout.close() stderr.close() env.cleanup()
"""The main entry point. Invoke as `http' or `python -m httpie'. """ import sys def main(): try: from httpie.core import main exit_status = main() except KeyboardInterrupt: from httpie.status import ExitStatus exit_status = ExitStatus.ERROR_CTRL_C sys.exit(exit_status.value) if __name__ == '__main__': main()
def http(*args, **kwargs): """ Run HTTPie and capture stderr/out and exit status. Invoke `httpie.core.main()` with `args` and `kwargs`, and return a `CLIResponse` subclass instance. The return value is either a `StrCLIResponse`, or `BytesCLIResponse` if unable to decode the output. The response has the following attributes: `stdout` is represented by the instance itself (print r) `stderr`: text written to stderr `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated. If you pass ``error_exit_ok=True``, then error exit statuses won't result into an exception. Example: $ http --auth=user:password GET httpbin.org/basic-auth/user/password >>> r = http('-a', 'user:pw', 'httpbin.org/basic-auth/user/pw') >>> type(r) == StrCLIResponse True >>> r.exit_status 0 >>> r.stderr '' >>> 'HTTP/1.1 200 OK' in r True >>> r.json == {'authenticated': True, 'user': '******'} True """ error_exit_ok = kwargs.pop('error_exit_ok', False) env = kwargs.get('env') if not env: env = kwargs['env'] = TestEnvironment() stdout = env.stdout stderr = env.stderr args = list(args) if '--debug' not in args and '--traceback' not in args: args = ['--traceback'] + args def dump_stderr(): stderr.seek(0) sys.stderr.write(stderr.read()) try: try: exit_status = main(args=args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) except SystemExit: if error_exit_ok: exit_status = httpie.ExitStatus.ERROR else: dump_stderr() raise except Exception: stderr.seek(0) sys.stderr.write(stderr.read()) raise else: if exit_status != httpie.ExitStatus.OK and not error_exit_ok: dump_stderr() raise Exception('Unexpected exit status: %s', exit_status) stdout.seek(0) stderr.seek(0) output = stdout.read() try: output = output.decode('utf8') except UnicodeDecodeError: # noinspection PyArgumentList r = BytesCLIResponse(output) else: # noinspection PyArgumentList r = StrCLIResponse(output) r.stderr = stderr.read() r.exit_status = exit_status if r.exit_status != httpie.ExitStatus.OK: sys.stderr.write(r.stderr) return r finally: stdout.close() stderr.close()
def http(*args, **kwargs): """ Invoke `httpie.core.main()` with `args` and `kwargs`, and return a unicode response. Return a `StrResponse`, or `BytesResponse` if unable to decode the output. The response has the following attributes: `stderr`: text written to stderr `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated except for SystemExit. """ env = kwargs.get('env') if not env: env = kwargs['env'] = TestEnvironment() stdout = env.stdout stderr = env.stderr try: try: exit_status = main(args=['--traceback'] + list(args), **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) except Exception: sys.stderr.write(stderr.read()) raise except SystemExit: exit_status = ExitStatus.ERROR stdout.seek(0) stderr.seek(0) output = stdout.read() try: r = StrResponse(output.decode('utf8')) except UnicodeDecodeError: r = BytesResponse(output) else: if COLOR not in r: # De-serialize JSON body if possible. if r.strip().startswith('{'): #noinspection PyTypeChecker r.json = json.loads(r) elif r.count('Content-Type:') == 1 and 'application/json' in r: try: j = r.strip()[r.strip().rindex('\r\n\r\n'):] except ValueError: pass else: try: r.json = json.loads(j) except ValueError: pass r.stderr = stderr.read() r.exit_status = exit_status return r finally: stdout.close() stderr.close()
def test_error_traceback(get_response): exc = ConnectionError('Connection aborted') exc.request = Request(method='GET', url='http://www.google.com') get_response.side_effect = exc with raises(ConnectionError): main(['--ignore-stdin', '--traceback', 'www.google.com'])
def http(*args, **kwargs): """ Invoke `httpie.core.main()` with `args` and `kwargs`, and return a unicode response. Return a `StrResponse`, or `BytesResponse` if unable to decode the output. The response has the following attributes: `stderr`: text written to stderr `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated except for SystemExit. """ env = kwargs.get('env') if not env: env = kwargs['env'] = TestEnvironment() try: try: exit_status = main(args=['--traceback'] + list(args), **kwargs) except Exception: sys.stderr.write(env.stderr.read()) raise except SystemExit: exit_status = exit.ERROR env.stdout.seek(0) env.stderr.seek(0) output = env.stdout.read() try: r = StrResponse(output.decode('utf8')) except UnicodeDecodeError: r = BytesResponse(output) else: if COLOR not in r: # De-serialize JSON body if possible. if r.strip().startswith('{'): #noinspection PyTypeChecker r.json = json.loads(r) elif r.count('Content-Type:') == 1 and 'application/json' in r: try: j = r.strip()[r.strip().rindex('\r\n\r\n'):] except ValueError: pass else: try: r.json = json.loads(j) except ValueError: pass r.stderr = env.stderr.read() r.exit_status = exit_status return r finally: env.stdout.close() env.stderr.close()
def http( *args, program_name='http', tolerate_error_exit_status=False, **kwargs, ) -> Union[StrCLIResponse, BytesCLIResponse]: # noinspection PyUnresolvedReferences """ Run HTTPie and capture stderr/out and exit status. Content writtent to devnull will be captured only if env.devnull is set manually. Invoke `httpie.core.main()` with `args` and `kwargs`, and return a `CLIResponse` subclass instance. The return value is either a `StrCLIResponse`, or `BytesCLIResponse` if unable to decode the output. Devnull is string when possible, bytes otherwise. The response has the following attributes: `stdout` is represented by the instance itself (print r) `stderr`: text written to stderr `devnull` text written to devnull. `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated. If you pass ``tolerate_error_exit_status=True``, then error exit statuses won't result into an exception. Example: $ http --auth=user:password GET httpbin.org/basic-auth/user/password >>> httpbin = getfixture('httpbin') >>> r = http('-a', 'user:pw', httpbin.url + '/basic-auth/user/pw') >>> type(r) == StrCLIResponse True >>> r.exit_status <ExitStatus.SUCCESS: 0> >>> r.stderr '' >>> 'HTTP/1.1 200 OK' in r True >>> r.json == {'authenticated': True, 'user': '******'} True """ env = kwargs.get('env') if not env: env = kwargs['env'] = MockEnvironment() stdout = env.stdout stderr = env.stderr devnull = env.devnull args = list(args) args_with_config_defaults = args + env.config.default_options add_to_args = [] if '--debug' not in args_with_config_defaults: if (not tolerate_error_exit_status and '--traceback' not in args_with_config_defaults): add_to_args.append('--traceback') if not any('--timeout' in arg for arg in args_with_config_defaults): add_to_args.append('--timeout=3') complete_args = [program_name, *add_to_args, *args] # print(' '.join(complete_args)) def dump_stderr(): stderr.seek(0) sys.stderr.write(stderr.read()) try: try: exit_status = main(args=complete_args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) except SystemExit: if tolerate_error_exit_status: exit_status = ExitStatus.ERROR else: dump_stderr() raise except Exception: stderr.seek(0) sys.stderr.write(stderr.read()) raise else: if (not tolerate_error_exit_status and exit_status != ExitStatus.SUCCESS): dump_stderr() raise ExitStatusError( 'httpie.core.main() unexpectedly returned' f' a non-zero exit status: {exit_status}' ) stdout.seek(0) stderr.seek(0) devnull.seek(0) output = stdout.read() devnull_output = devnull.read() try: output = output.decode('utf8') except UnicodeDecodeError: r = BytesCLIResponse(output) else: r = StrCLIResponse(output) try: devnull_output = devnull_output.decode('utf8') except Exception: pass r.devnull = devnull_output r.stderr = stderr.read() r.exit_status = exit_status if r.exit_status != ExitStatus.SUCCESS: sys.stderr.write(r.stderr) return r finally: devnull.close() stdout.close() stderr.close() env.cleanup()
def exec_request(httpie_args): args = httpie_args.splitlines() args = [x.strip() for x in args] httpie.main(args)
def http(*args, **kwargs): """ Run HTTPie and capture stderr/out and exit status. Invoke `httpie.core.main()` with `args` and `kwargs`, and return a `CLIResponse` subclass instance. The return value is either a `StrCLIResponse`, or `BytesCLIResponse` if unable to decode the output. The response has the following attributes: `stdout` is represented by the instance itself (print r) `stderr`: text written to stderr `exit_status`: the exit status `json`: decoded JSON (if possible) or `None` Exceptions are propagated except for SystemExit. $ http --auth=user:password GET httpbin.org/basic-auth/user/password >>> r = http('-a', 'user:pw', httpbin('/basic-auth/user/pw')) >>> type(r) == StrCLIResponse True >>> r.exit_status 0 >>> r.stderr '' >>> 'HTTP/1.1 200 OK' in r True >>> r.json == {'authenticated': True, 'user': '******'} True """ env = kwargs.get('env') if not env: env = kwargs['env'] = TestEnvironment() stdout = env.stdout stderr = env.stderr args = list(args) if '--debug' not in args and '--traceback' not in args: args = ['--traceback'] + args try: try: exit_status = main(args=args, **kwargs) if '--download' in args: # Let the progress reporter thread finish. time.sleep(.5) except Exception: sys.stderr.write(stderr.read()) raise except SystemExit: exit_status = httpie.ExitStatus.ERROR stdout.seek(0) stderr.seek(0) output = stdout.read() try: output = output.decode('utf8') except UnicodeDecodeError: # noinspection PyArgumentList r = BytesCLIResponse(output) else: # noinspection PyArgumentList r = StrCLIResponse(output) r.stderr = stderr.read() r.exit_status = exit_status return r finally: stdout.close() stderr.close()
"""The main entry point. Invoke as `http' or `python -m httpie'. """ def main(): try: from httpie.core import main exit_status = main() except KeyboardInterrupt: from httpie.status import ExitStatus exit_status = ExitStatus.ERROR_CTRL_C return exit_status.value if __name__ == '__main__': # pragma: nocover import sys sys.exit(main())