Skip to content

Commit

Permalink
Modularized output, refactoring
Browse files Browse the repository at this point in the history
Making it ready for output formatting plugin API.
  • Loading branch information
jkbrzt committed Apr 27, 2014
1 parent c06598a commit 05db75b
Show file tree
Hide file tree
Showing 24 changed files with 747 additions and 765 deletions.
2 changes: 1 addition & 1 deletion httpie/cli.py
Expand Up @@ -13,7 +13,7 @@
from .plugins.builtin import BuiltinAuthPlugin
from .plugins import plugin_manager
from .sessions import DEFAULT_SESSIONS_DIR
from .output import AVAILABLE_STYLES, DEFAULT_STYLE
from .output.processors.colors import AVAILABLE_STYLES, DEFAULT_STYLE
from .input import (Parser, AuthCredentialsArgType, KeyValueArgType,
SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ALL_ITEMS,
OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD,
Expand Down
4 changes: 4 additions & 0 deletions httpie/compat.py
Expand Up @@ -34,6 +34,7 @@
# noinspection PyCompatibility
from UserDict import DictMixin

# noinspection PyShadowingBuiltins
class OrderedDict(dict, DictMixin):
# Copyright (c) 2009 Raymond Hettinger
#
Expand All @@ -56,6 +57,7 @@ class OrderedDict(dict, DictMixin):
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
# noinspection PyMissingConstructor
def __init__(self, *args, **kwds):
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d'
Expand All @@ -68,6 +70,7 @@ def __init__(self, *args, **kwds):

def clear(self):
self.__end = end = []
# noinspection PyUnusedLocal
end += [None, end, end] # sentinel node for doubly linked list
self.__map = {} # key --> [key, prev, next]
dict.clear(self)
Expand Down Expand Up @@ -139,6 +142,7 @@ def __repr__(self):
def copy(self):
return self.__class__(self)

# noinspection PyMethodOverriding
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
Expand Down
1 change: 0 additions & 1 deletion httpie/config.py
Expand Up @@ -43,7 +43,6 @@ def path(self):
raise
return path

@property
def is_new(self):
return not os.path.exists(self._get_path())

Expand Down
68 changes: 68 additions & 0 deletions httpie/context.py
@@ -0,0 +1,68 @@
import os
import sys

from requests.compat import is_windows

from httpie.config import DEFAULT_CONFIG_DIR, Config


class Environment(object):
"""
Information about the execution context
(standard streams, config directory, etc).
By default, it represents the actual environment.
All of the attributes can be overwritten though, which
is used by the test suite to simulate various scenarios.
"""
is_windows = is_windows
config_dir = DEFAULT_CONFIG_DIR
colors = 256 if '256color' in os.environ.get('TERM', '') else 88
stdin = sys.stdin
stdin_isatty = stdin.isatty()
stdin_encoding = None
stdout = sys.stdout
stdout_isatty = stdout.isatty()
stdout_encoding = None
stderr = sys.stderr
stderr_isatty = stderr.isatty()
if is_windows:
# noinspection PyUnresolvedReferences
from colorama.initialise import wrap_stream
stdout = wrap_stream(stdout, convert=None, strip=None,
autoreset=True, wrap=True)
stderr = wrap_stream(stderr, convert=None, strip=None,
autoreset=True, wrap=True)

def __init__(self, **kwargs):
"""
Use keyword arguments to overwrite
any of the class attributes for this instance.
"""
assert all(hasattr(type(self), attr) for attr in kwargs.keys())
self.__dict__.update(**kwargs)

# Keyword arguments > stream.encoding > default utf8
if self.stdin_encoding is None:
self.stdin_encoding = getattr(
self.stdin, 'encoding', None) or 'utf8'
if self.stdout_encoding is None:
actual_stdout = self.stdout
if is_windows:
from colorama import AnsiToWin32
if isinstance(self.stdout, AnsiToWin32):
actual_stdout = self.stdout.wrapped
self.stdout_encoding = getattr(
actual_stdout, 'encoding', None) or 'utf8'

@property
def config(self):
if not hasattr(self, '_config'):
self._config = Config(directory=self.config_dir)
if self._config.is_new():
self._config.save()
else:
self._config.load()
return self._config
30 changes: 16 additions & 14 deletions httpie/core.py
Expand Up @@ -2,29 +2,31 @@
Invocation flow:
1. Read, validate and process the input (args, `stdin`).
2. Create and send a request.
3. Stream, and possibly process and format, the requested parts
of the request-response exchange.
4. Simultaneously write to `stdout`
5. Exit.
1. Read, validate and process the input (args, `stdin`).
2. Create and send a request.
3. Stream, and possibly process and format, the parts
of the request-response exchange selected by output options.
4. Simultaneously write to `stdout`
5. Exit.
"""
import sys
import errno

import requests
from httpie import __version__ as httpie_version
from requests import __version__ as requests_version
from pygments import __version__ as pygments_version

from .compat import str, bytes, is_py3
from .client import get_response
from .downloads import Download
from .models import Environment
from .output import build_output_stream, write, write_with_colors_win_py3
from . import ExitStatus
from .plugins import plugin_manager
from httpie import __version__ as httpie_version, ExitStatus
from httpie.compat import str, bytes, is_py3
from httpie.client import get_response
from httpie.downloads import Download
from httpie.context import Environment
from httpie.plugins import plugin_manager
from httpie.output.streams import (
build_output_stream,
write, write_with_colors_win_py3
)


def get_exit_status(http_status, follow=False):
Expand Down
8 changes: 4 additions & 4 deletions httpie/downloads.py
Expand Up @@ -12,10 +12,10 @@
from time import sleep, time
from mailbox import Message

from .output import RawStream
from .models import HTTPResponse
from .utils import humanize_bytes
from .compat import urlsplit
from httpie.output.streams import RawStream
from httpie.models import HTTPResponse
from httpie.utils import humanize_bytes
from httpie.compat import urlsplit


PARTIAL_CONTENT = 206
Expand Down
17 changes: 6 additions & 11 deletions httpie/input.py
Expand Up @@ -132,8 +132,7 @@ def parse_args(self, env, args=None, namespace=None):
if not self.args.ignore_stdin and not env.stdin_isatty:
self._body_from_file(self.env.stdin)
if not (self.args.url.startswith((HTTP, HTTPS))):
# Default to 'https://' if invoked as `https args`.
scheme = HTTPS if self.env.progname == 'https' else HTTP
scheme = HTTP

# See if we're using curl style shorthand for localhost (:3000/foo)
shorthand = re.match(r'^:(?!:)(\d*)(/?.*)$', self.args.url)
Expand Down Expand Up @@ -277,10 +276,8 @@ def _guess_method(self):
# and the first ITEM is now incorrectly in `args.url`.
try:
# Parse the URL as an ITEM and store it as the first ITEM arg.
self.args.items.insert(
0,
KeyValueArgType(*SEP_GROUP_ALL_ITEMS).__call__(self.args.url)
)
self.args.items.insert(0, KeyValueArgType(
*SEP_GROUP_ALL_ITEMS).__call__(self.args.url))

except ArgumentTypeError as e:
if self.args.traceback:
Expand All @@ -292,11 +289,9 @@ def _guess_method(self):
self.args.url = self.args.method
# Infer the method
has_data = (
(not self.args.ignore_stdin and
not self.env.stdin_isatty) or any(
item.sep in SEP_GROUP_DATA_ITEMS
for item in self.args.items
)
(not self.args.ignore_stdin and not self.env.stdin_isatty)
or any(item.sep in SEP_GROUP_DATA_ITEMS
for item in self.args.items)
)
self.args.method = HTTP_POST if has_data else HTTP_GET

Expand Down
73 changes: 1 addition & 72 deletions httpie/models.py
@@ -1,75 +1,4 @@
import os
import sys

from .config import DEFAULT_CONFIG_DIR, Config
from .compat import urlsplit, is_windows, str


class Environment(object):
"""Holds information about the execution context.
Groups various aspects of the environment in a changeable object
and allows for mocking.
"""

is_windows = is_windows

progname = os.path.basename(sys.argv[0])
if progname not in ['http', 'https']:
progname = 'http'

config_dir = DEFAULT_CONFIG_DIR

# Can be set to 0 to disable colors completely.
colors = 256 if '256color' in os.environ.get('TERM', '') else 88

stdin = sys.stdin
stdin_isatty = sys.stdin.isatty()

stdout_isatty = sys.stdout.isatty()
stderr_isatty = sys.stderr.isatty()
if is_windows:
# noinspection PyUnresolvedReferences
from colorama.initialise import wrap_stream
stdout = wrap_stream(sys.stdout, convert=None,
strip=None, autoreset=True, wrap=True)
stderr = wrap_stream(sys.stderr, convert=None,
strip=None, autoreset=True, wrap=True)
else:
stdout = sys.stdout
stderr = sys.stderr

stdin_encoding = None
stdout_encoding = None

def __init__(self, **kwargs):
assert all(hasattr(type(self), attr)
for attr in kwargs.keys())
self.__dict__.update(**kwargs)

if self.stdin_encoding is None:
self.stdin_encoding = getattr(
self.stdin, 'encoding', None) or 'utf8'

if self.stdout_encoding is None:
actual_stdout = self.stdout
if is_windows:
from colorama import AnsiToWin32
if isinstance(self.stdout, AnsiToWin32):
actual_stdout = self.stdout.wrapped
self.stdout_encoding = getattr(
actual_stdout, 'encoding', None) or 'utf8'

@property
def config(self):
if not hasattr(self, '_config'):
self._config = Config(directory=self.config_dir)
if self._config.is_new:
self._config.save()
else:
self._config.load()
return self._config
from .compat import urlsplit, str


class HTTPMessage(object):
Expand Down

0 comments on commit 05db75b

Please sign in to comment.