diff --git a/README.md b/README.md index 0007aea..32a3d24 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,18 @@ No matters your religion, IMAP4 or HTTP, you should not worries about accessing using kiss-headers from python interpreter

-### Installation +## Your support + +Please ⭐ this repository if this project helped you! + +### ✨ Installation Whatever you like, use `Pipenv` or `pip`, it simply work. We are expecting you to have python 3.6+ installed. ```sh pip install kiss-headers ``` -### Usage +### 🍰 Usage `parse_it()` method take `bytes`, `str`, `fp` or `dict` and give you back a `Headers` object. @@ -50,10 +54,10 @@ headers = parse_it(response.headers) 'Content-Type' in headers # output: True 'Content_type' in headers # output: True -headers.content_type # output : application/json +str(headers.content_type) # output : application/json 'application/json' in headers.content_type # output: True -headers.content_type.charset # output : utf-8 +str(headers.content_type.charset) # output : utf-8 ``` ## 👤 Contributing diff --git a/kiss_headers/utils.py b/kiss_headers/utils.py index c0a6d30..2bfccd8 100644 --- a/kiss_headers/utils.py +++ b/kiss_headers/utils.py @@ -30,6 +30,11 @@ def __init__(self, head: str, content: str): if '=' in member: key, value = tuple(member.split('=', maxsplit=1)) + # avoid confusing base64 look alike single value for (key, value) + if value.count('=') == len(value) or len(value) == 0: + self._not_valued_attrs.append(member) + continue + if key not in self._valued_attrs: self._valued_attrs[key] = value else: @@ -83,7 +88,7 @@ def __iter__(self) -> Iterator[Tuple[str, Optional[str]]]: def __eq__(self, other) -> bool: if isinstance(other, str): - return self.content == other + return self.content == other or other in self._not_valued_attrs if isinstance(other, Header): return self.normalized_name == other.normalized_name and self.content == other.content raise TypeError('Cannot compare type {type_} to an Header. Use str or Header.'.format(type_=type(other))) @@ -95,7 +100,7 @@ def __repr__(self) -> str: return "{head}: {content}".format(head=self._head, content=self._content) def __dir__(self) -> Iterable[str]: - return super().__dir__() + list(self._valued_attrs.keys()) + return super().__dir__() + list(self._valued_attrs_normalized.keys()) @property def attrs(self) -> List[str]: @@ -116,6 +121,9 @@ def get(self, attr: str) -> Optional[str]: return self._valued_attrs[attr] def __getitem__(self, item: str) -> Union[str, List[str]]: + """ + This method will allow you to retrieve attribute value using the bracket syntax, list-like. + """ normalized_item = Header.normalize_name(item) if item in self._valued_attrs: @@ -126,13 +134,17 @@ def __getitem__(self, item: str) -> Union[str, List[str]]: raise KeyError( "'{item}' attribute is not defined within '{header}' header.".format(item=item, header=self.name)) - if isinstance(value, str): - if value.startswith('"') and value.endswith('"'): - return value[1:-1] + # Unquote value if necessary + if isinstance(value, str) and value.startswith('"') and value.endswith('"'): + return value[1:-1] return value def __getattr__(self, item) -> str: + """ + All the magic happen here, this method should be invoked when trying to call (not declared) properties. + For instance, calling self.charset should end up here and be replaced by self['charset']. + """ if item not in self._valued_attrs and Header.normalize_name(item) not in self._valued_attrs_normalized: raise AttributeError("'{item}' attribute is not defined within '{header}' header.".format(item=item, header=self.name)) @@ -176,6 +188,9 @@ class Headers: connection: Header keep_alive: Header + x_cache: Header + via: Header + accept: Header accept_charset: Header accept_encoding: Header @@ -222,6 +237,16 @@ def __iter__(self): for header in self._headers: yield header + def to_dict(self) -> Dict[str, str]: + """ + Provide a dict output of current headers + """ + return dict( + [ + (header.name, header.content) for header in self + ] + ) + def __eq__(self, other: 'Headers') -> bool: if len(other) != len(self): return False @@ -235,8 +260,14 @@ def __eq__(self, other: 'Headers') -> bool: def __len__(self) -> int: return len(self._headers) + def __str__(self): + return self.__repr__() + + def __repr__(self) -> str: + return '\n'.join([header.__repr__() for header in self]) + def __getitem__(self, item: str) -> Union[Header, List[Header]]: - item = item.lower().replace('-', '_') + item = Header.normalize_name(item) if item not in self: raise KeyError("'{item}' header is not defined in headers.".format(item=item)) diff --git a/kiss_headers/version.py b/kiss_headers/version.py index bc08299..0701c8f 100644 --- a/kiss_headers/version.py +++ b/kiss_headers/version.py @@ -2,5 +2,5 @@ Expose version """ -__version__ = "1.0.0" +__version__ = "1.0.1" VERSION = __version__.split('.')