tavalidate-0.0.6/ 0000755 0000765 0000024 00000000000 14001530205 015114 5 ustar douglasliu staff 0000000 0000000 tavalidate-0.0.6/PKG-INFO 0000644 0000765 0000024 00000006414 14001530205 016216 0 ustar douglasliu staff 0000000 0000000 Metadata-Version: 2.1
Name: tavalidate
Version: 0.0.6
Summary: Utilities to help you validate and save Tavern response.
Home-page: https://github.com/sohoffice/tavalidate
Author: Douglas Liu
Author-email: douglas@sohoffice.com
License: UNKNOWN
Description: tavalidate, utilities to help you validate [Tavern](https://tavern.readthedocs.io/en/latest/) response.
Installation
------------
Tavalidate can be installed through pip.
```
pip install tavalidate
```
XML Validate
----
Tavern has great built-in Json support, but things are difficult when it comes to XML.
Use tavalidate.xmlv package to validate XML response.
XML validation example:
```
response:
status_code: 200
verify_response_with:
function: tavalidate:assert_xml
extra_kwargs:
expected: |
!anyint
```
Simply put, pass the expected xml as an argument to the `tavalidate.xmlv.validate` function. The
function will validate the xml structure, node value and attribute value.
### extra_kwargs
Below are the supported extra kwargs of `tavalidate.xmlv.validate` function.
#### expected
This is the expected XML string.
You may use some (not all) of the tavern magic values to match data of your specified type:
- !anything: This matches value of any type.
- !anystr: Matches any string
- !anyint: Matches any integer
- !anyfloat: Matches any float
- !anybool: Matches any boolean
#### strict
Use `strict: True` if you want to make sure there's no extra tag in the response.
#### array
Since XML do not have the concept of array. When validating an array-like element, the same
number of children of the same tag must exist. Regardless whether strict mode is used or not.
All element in corresponding order must match for the container to match.
XML Save
----
Use tavalidate.xmlv package to save XML response.
It allows you to use [XPath](https://en.wikipedia.org/wiki/XPath) to specify the value to save
inside the xml document. If the XPath somehow selects multiple nodes, tavalidate will print a
warning, but the first value will still be saved.
XML save example:
```
response:
save:
$ext:
function: tavalidate:save_xml
extra_kwargs:
variables:
bar: '/foo/bar/text()'
at1: '/foo/@at1'
```
Logging
-------
Configure the logger `tavalidate` so you can see the response body and other logs in
DEBUG level.
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Description-Content-Type: text/markdown
tavalidate-0.0.6/README.md 0000644 0000765 0000024 00000004176 14001530020 016376 0 ustar douglasliu staff 0000000 0000000 tavalidate, utilities to help you validate [Tavern](https://tavern.readthedocs.io/en/latest/) response.
Installation
------------
Tavalidate can be installed through pip.
```
pip install tavalidate
```
XML Validate
----
Tavern has great built-in Json support, but things are difficult when it comes to XML.
Use tavalidate.xmlv package to validate XML response.
XML validation example:
```
response:
status_code: 200
verify_response_with:
function: tavalidate:assert_xml
extra_kwargs:
expected: |
!anyint
```
Simply put, pass the expected xml as an argument to the `tavalidate.xmlv.validate` function. The
function will validate the xml structure, node value and attribute value.
### extra_kwargs
Below are the supported extra kwargs of `tavalidate.xmlv.validate` function.
#### expected
This is the expected XML string.
You may use some (not all) of the tavern magic values to match data of your specified type:
- !anything: This matches value of any type.
- !anystr: Matches any string
- !anyint: Matches any integer
- !anyfloat: Matches any float
- !anybool: Matches any boolean
#### strict
Use `strict: True` if you want to make sure there's no extra tag in the response.
#### array
Since XML do not have the concept of array. When validating an array-like element, the same
number of children of the same tag must exist. Regardless whether strict mode is used or not.
All element in corresponding order must match for the container to match.
XML Save
----
Use tavalidate.xmlv package to save XML response.
It allows you to use [XPath](https://en.wikipedia.org/wiki/XPath) to specify the value to save
inside the xml document. If the XPath somehow selects multiple nodes, tavalidate will print a
warning, but the first value will still be saved.
XML save example:
```
response:
save:
$ext:
function: tavalidate:save_xml
extra_kwargs:
variables:
bar: '/foo/bar/text()'
at1: '/foo/@at1'
```
Logging
-------
Configure the logger `tavalidate` so you can see the response body and other logs in
DEBUG level.
tavalidate-0.0.6/setup.cfg 0000644 0000765 0000024 00000000046 14001530205 016735 0 ustar douglasliu staff 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
tavalidate-0.0.6/setup.py 0000644 0000765 0000024 00000001375 14001527202 016637 0 ustar douglasliu staff 0000000 0000000 import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="tavalidate",
version="0.0.6",
author="Douglas Liu",
author_email="douglas@sohoffice.com",
description="Utilities to help you validate and save Tavern response.",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/sohoffice/tavalidate",
packages=setuptools.find_packages(),
install_requires=[
'lxml>=4.0.0'
],
classifiers=(
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent"
),
)
tavalidate-0.0.6/tavalidate/ 0000755 0000765 0000024 00000000000 14001530205 017232 5 ustar douglasliu staff 0000000 0000000 tavalidate-0.0.6/tavalidate/__init__.py 0000644 0000765 0000024 00000000205 13627166017 021363 0 ustar douglasliu staff 0000000 0000000 from tavalidate.xmls import do_save_xml
from tavalidate.xmlv import do_assert_xml
save_xml = do_save_xml
assert_xml = do_assert_xml
tavalidate-0.0.6/tavalidate/log.py 0000644 0000765 0000024 00000000071 13627221614 020401 0 ustar douglasliu staff 0000000 0000000 import logging
logger = logging.getLogger('tavalidate')
tavalidate-0.0.6/tavalidate/test_xmls.py 0000644 0000765 0000024 00000001776 13627220170 021653 0 ustar douglasliu staff 0000000 0000000 from unittest import TestCase
from tavalidate.test_xmlv import DummyResponse
from tavalidate.xmls import save_xml
class Test(TestCase):
def test_save_xml(self):
resp = DummyResponse("""
str
""")
x = save_xml(resp, variables={
'bar': '/foo/bar/text()',
'at1': '/foo/@at1',
'at2': '/foo/bar/@at2'
})
assert x['bar'] == 'str'
assert x['at1'] == '1'
assert x['at2'] == '2'
def test_save_xml_with_encoding_declaration(self):
resp = DummyResponse(
"""
S""")
with self.assertRaises(AssertionError):
save_xml(resp, variables={
'notFound': '/not/found'
})
x = save_xml(resp, variables={
'status': '/foo/statusCode/text()'
})
assert x['status'] == 'S'
tavalidate-0.0.6/tavalidate/test_xmlv.py 0000644 0000765 0000024 00000007720 14001530131 021635 0 ustar douglasliu staff 0000000 0000000 from unittest import TestCase
from tavalidate.xmlv import assert_xml
class Test(TestCase):
def test_assert_xml_root(self):
resp = DummyResponse("""
""")
assert_xml(resp, expected="""
""")
# Different only in whitespaces
assert_xml(resp, expected="""""")
assert_xml(DummyResponse(""""""), expected="""
""")
# Expect extra child
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
# Expect different root tag
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
# Expect less attribute
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""", strict=True)
# Expect extra attribute
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
# Expect different attribute value
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
def test_assert_xml_child(self):
resp = DummyResponse("""
text
""")
assert_xml(resp, expected="""
text
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
text
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
Different text
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
""")
assert_xml(resp, expected="""
!anything
""")
resp2 = DummyResponse("""
True
""")
assert_xml(resp2, expected="""
!anybool
""")
def test_assert_xml_array(self):
resp = DummyResponse("""
text1
text2
""")
assert_xml(resp, expected="""
text1
text2
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
text2
text1
""")
with self.assertRaises(AssertionError):
assert_xml(resp, expected="""
text1
text2
text3
""")
class DummyResponse(object):
def __init__(self, text):
self.text = text
tavalidate-0.0.6/tavalidate/xmls.py 0000644 0000765 0000024 00000002125 13627220623 020604 0 ustar douglasliu staff 0000000 0000000 from io import BytesIO
from lxml import etree
from typing import Mapping
from box import Box
from tavalidate.log import logger
def do_save_xml(resp, **kwargs):
"""
Extract data from response xml body
:param resp:
:param kwargs.variables: variable name -> xpath mapping.
:return:
"""
source_xml = resp.text
logger.debug("Response body: {}".format(source_xml))
variables: Mapping = kwargs['variables']
source_et = etree.parse(BytesIO(bytes(source_xml, "UTF-8")))
assert source_et is not None, "Can not parse response body"
data = dict()
for var in variables.items():
it = _extract(source_et, var[1])
assert it is not None, "Can not read {} from response".format(var[1])
data[var[0]] = it
logger.debug("{} => {}".format(var[0], it))
return Box(data)
def _extract(root, xp):
ar = root.xpath(xp)
if len(ar) <= 0:
return None
if len(ar) > 1:
logger.info("XPath {} produces more than 1 results, the first is used."
.format(xp))
return ar[0]
save_xml = do_save_xml
tavalidate-0.0.6/tavalidate/xmlv.py 0000644 0000765 0000024 00000010124 14001527712 020601 0 ustar douglasliu staff 0000000 0000000 import xml.etree.ElementTree as ET
from tavalidate.log import logger
def do_assert_xml(resp, **kwargs):
"""
Assert the xml structure in response body is the same as the expected xml.
:param resp:
:param expected: The expected xml string
:param strict: The response xml should not have extra attributes or children
:return:
"""
expected_xml = kwargs['expected']
strict = kwargs.get('strict', False)
source_xml = resp.text
logger.debug("Response body: {}".format(source_xml))
source_et = ET.fromstring(source_xml)
expected_et = ET.fromstring(expected_xml)
assert source_et is not None, "Can not parse response body"
assert expected_et is not None, "Can not parse expected body"
_assert_node(source_et, expected_et, strict)
def _assert_node(source, expected, strict):
assert source.tag == expected.tag, \
"Tag {} is different from expected {}".format(source.tag, expected.tag)
for attr in expected.attrib:
assert attr in source.attrib, \
"Attribute {} not found in {}".format(attr, source.tag)
assert _assert_value(source.attrib[attr], expected.attrib[attr]), \
"Expecting attribute {}, but get {}".format(expected.attrib[attr],
source.attrib[attr])
if strict:
for attr in source.attrib:
assert attr in expected.attrib, \
"Attribute {} in {} is unexpected and we're in strict mode".format(
attr, expected.tag)
assert _assert_value(source.text, expected.text), \
"Node value {} not equal to expected {} in {}".format(
source.text, expected.text, expected.tag)
validated_child_tags = set()
for child in expected:
if child.tag not in validated_child_tags:
validated_child_tags.add(child.tag)
expected_children = expected.iter(child.tag)
source_children = source.iter(child.tag)
expected_list = list(expected_children)
source_list = list(source_children)
assert source_children is not None, \
"Tag {} not found in {}".format(child.tag, expected.tag)
for idx, expected_child in enumerate(expected_list):
assert idx < len(source_list), \
"Tag {} inside {} should have {} occurrences, " \
"but {} is found".format(child.tag, source.tag,
len(expected_list),
len(source_list))
source_child = source_list[idx]
_assert_node(source_child, expected_child, strict)
if strict:
for child in source:
expected_child = source.find(child.tag)
assert expected_child is not None, \
"Tag {} in {} is unexpected and we're in strict mode.".format(
child, expected.tag)
def _assert_value(source: str, expected: str):
if source is None and expected is None:
return True
if expected is None and source is not None and not source.strip():
return True
if expected is None:
return False
expected_striped = expected.strip()
if source is None and not expected_striped:
return True
if expected_striped == "!anything":
return True
elif expected_striped == "!anyint":
try:
int(source.strip())
return True
except ValueError:
assert False, "{} is not a integer".format(source)
elif expected_striped == "!anyfloat":
try:
float(source.strip())
return True
except ValueError:
assert False, "{} is not a float".format(source)
elif expected_striped == "!anystr":
return True
elif expected_striped == "!anybool":
try:
bool(source.strip())
return True
except ValueError:
assert False, "{} is not a bool".format(source)
if source is None:
return False
return source.strip() == expected_striped
assert_xml = do_assert_xml
tavalidate-0.0.6/tavalidate.egg-info/ 0000755 0000765 0000024 00000000000 14001530205 020724 5 ustar douglasliu staff 0000000 0000000 tavalidate-0.0.6/tavalidate.egg-info/PKG-INFO 0000644 0000765 0000024 00000006414 14001530205 022026 0 ustar douglasliu staff 0000000 0000000 Metadata-Version: 2.1
Name: tavalidate
Version: 0.0.6
Summary: Utilities to help you validate and save Tavern response.
Home-page: https://github.com/sohoffice/tavalidate
Author: Douglas Liu
Author-email: douglas@sohoffice.com
License: UNKNOWN
Description: tavalidate, utilities to help you validate [Tavern](https://tavern.readthedocs.io/en/latest/) response.
Installation
------------
Tavalidate can be installed through pip.
```
pip install tavalidate
```
XML Validate
----
Tavern has great built-in Json support, but things are difficult when it comes to XML.
Use tavalidate.xmlv package to validate XML response.
XML validation example:
```
response:
status_code: 200
verify_response_with:
function: tavalidate:assert_xml
extra_kwargs:
expected: |
!anyint
```
Simply put, pass the expected xml as an argument to the `tavalidate.xmlv.validate` function. The
function will validate the xml structure, node value and attribute value.
### extra_kwargs
Below are the supported extra kwargs of `tavalidate.xmlv.validate` function.
#### expected
This is the expected XML string.
You may use some (not all) of the tavern magic values to match data of your specified type:
- !anything: This matches value of any type.
- !anystr: Matches any string
- !anyint: Matches any integer
- !anyfloat: Matches any float
- !anybool: Matches any boolean
#### strict
Use `strict: True` if you want to make sure there's no extra tag in the response.
#### array
Since XML do not have the concept of array. When validating an array-like element, the same
number of children of the same tag must exist. Regardless whether strict mode is used or not.
All element in corresponding order must match for the container to match.
XML Save
----
Use tavalidate.xmlv package to save XML response.
It allows you to use [XPath](https://en.wikipedia.org/wiki/XPath) to specify the value to save
inside the xml document. If the XPath somehow selects multiple nodes, tavalidate will print a
warning, but the first value will still be saved.
XML save example:
```
response:
save:
$ext:
function: tavalidate:save_xml
extra_kwargs:
variables:
bar: '/foo/bar/text()'
at1: '/foo/@at1'
```
Logging
-------
Configure the logger `tavalidate` so you can see the response body and other logs in
DEBUG level.
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Description-Content-Type: text/markdown
tavalidate-0.0.6/tavalidate.egg-info/SOURCES.txt 0000644 0000765 0000024 00000000472 14001530205 022613 0 ustar douglasliu staff 0000000 0000000 README.md
setup.py
tavalidate/__init__.py
tavalidate/log.py
tavalidate/test_xmls.py
tavalidate/test_xmlv.py
tavalidate/xmls.py
tavalidate/xmlv.py
tavalidate.egg-info/PKG-INFO
tavalidate.egg-info/SOURCES.txt
tavalidate.egg-info/dependency_links.txt
tavalidate.egg-info/requires.txt
tavalidate.egg-info/top_level.txt tavalidate-0.0.6/tavalidate.egg-info/dependency_links.txt 0000644 0000765 0000024 00000000001 14001530205 024772 0 ustar douglasliu staff 0000000 0000000
tavalidate-0.0.6/tavalidate.egg-info/requires.txt 0000644 0000765 0000024 00000000014 14001530205 023317 0 ustar douglasliu staff 0000000 0000000 lxml>=4.0.0
tavalidate-0.0.6/tavalidate.egg-info/top_level.txt 0000644 0000765 0000024 00000000013 14001530205 023450 0 ustar douglasliu staff 0000000 0000000 tavalidate