pax_global_header00006660000000000000000000000064136447125300014517gustar00rootroot0000000000000052 comment=da33b6bd54e8e434a8218034f41678ec9d4a826e jpadilla-django-rest-framework-xml-da33b6b/000077500000000000000000000000001364471253000207715ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/.flake8000066400000000000000000000000711364471253000221420ustar00rootroot00000000000000[flake8] max-line-length = 79 extend-ignore = E203, E501 jpadilla-django-rest-framework-xml-da33b6b/.github/000077500000000000000000000000001364471253000223315ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/.github/FUNDING.yml000066400000000000000000000001021364471253000241370ustar00rootroot00000000000000# These are supported funding model platforms github: [jpadilla] jpadilla-django-rest-framework-xml-da33b6b/.github/workflows/000077500000000000000000000000001364471253000243665ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/.github/workflows/main.yml000066400000000000000000000041511364471253000260360ustar00rootroot00000000000000--- name: CI on: push: branches: ["master"] pull_request: branches: ["master"] # Allow rebuilds via API. repository_dispatch: types: rebuild jobs: tests: name: "Python ${{ matrix.python-version }} on ${{ matrix.platform }}" runs-on: "${{ matrix.platform }}" env: USING_COVERAGE: '3.8' strategy: matrix: platform: ["ubuntu-latest"] python-version: ["3.5", "3.6", "3.7", "3.8"] steps: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v1" with: python-version: "${{ matrix.python-version }}" - name: "Install dependencies" run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel python -m pip install --upgrade virtualenv tox tox-gh-actions - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" env: PLATFORM: ${{ matrix.platform }} package: name: "Build & verify package" runs-on: "ubuntu-latest" steps: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v1" with: python-version: "3.8" - name: "Install pep517 and twine" run: "python -m pip install pep517 twine" - name: "Build package" run: "python -m pep517.build --source --binary ." - name: "List result" run: "ls -l dist" - name: "Check long_description" run: "python -m twine check dist/*" install-dev: strategy: matrix: os: ["ubuntu-latest", "windows-latest", "macos-latest"] name: "Verify dev env" runs-on: "${{ matrix.os }}" steps: - uses: "actions/checkout@v2" - uses: "actions/setup-python@v1" with: python-version: "3.8" - name: "Install in dev mode" run: "python -m pip install -e .[dev]" - name: "Import package" run: "python -c 'import rest_framework_xml; print(rest_framework_xml.__version__)'" jpadilla-django-rest-framework-xml-da33b6b/.github/workflows/publish.yml000066400000000000000000000015411364471253000265600ustar00rootroot00000000000000# This workflows will upload a Python Package using Twine when a release is created # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries name: Upload Python Package on: release: types: [created] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v1 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel twine - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python setup.py sdist bdist_wheel twine upload dist/* jpadilla-django-rest-framework-xml-da33b6b/.gitignore000066400000000000000000000003001364471253000227520ustar00rootroot00000000000000*.pyc *.db *~ .* html/ htmlcov/ coverage/ build/ dist/ *.egg-info/ MANIFEST bin/ include/ lib/ local/ !.gitignore !.github !.flake8 !.isort.cfg !.pre-commit-config.yaml pip-wheel-metadata jpadilla-django-rest-framework-xml-da33b6b/.isort.cfg000066400000000000000000000001001364471253000226570ustar00rootroot00000000000000[settings] known_third_party = django,rest_framework,setuptools jpadilla-django-rest-framework-xml-da33b6b/.pre-commit-config.yaml000066400000000000000000000013171364471253000252540ustar00rootroot00000000000000repos: - repo: https://github.com/psf/black rev: 19.10b0 hooks: - id: black language_version: python3.8 - repo: https://gitlab.com/pycqa/flake8 rev: 3.7.9 hooks: - id: flake8 language_version: python3.8 - repo: https://github.com/asottile/seed-isort-config rev: v1.9.4 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort rev: v4.3.21 hooks: - id: isort additional_dependencies: [toml] language_version: python3.8 - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: debug-statements jpadilla-django-rest-framework-xml-da33b6b/LICENSE000066400000000000000000000027601364471253000220030ustar00rootroot00000000000000Copyright (c) 2014, José Padilla All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jpadilla-django-rest-framework-xml-da33b6b/MANIFEST.in000066400000000000000000000000751364471253000225310ustar00rootroot00000000000000recursive-exclude * __pycache__ recursive-exclude * *.py[co] jpadilla-django-rest-framework-xml-da33b6b/README.md000066400000000000000000000052561364471253000222600ustar00rootroot00000000000000# REST Framework XML [![build-status-image]][github-action] [![pypi-version]][pypi] **XML support for Django REST Framework** Full documentation for the project is available at [http://jpadilla.github.io/django-rest-framework-xml][docs]. ## Overview XML support extracted as a third party package directly from the official Django REST Framework implementation. It requires the [defusedxml][defusedxml] package only because it safeguards against some security issues that were discovered. **Note**: XML output provided is an ad-hoc format that isn't formally described. If you have specific XML requirements you'll need to write your own XML parsers/renderers in order to fully control the representation. ## Requirements * Python 3.5+ * Django 2.2+ * Django REST Framework 3.11+ ## Installation Install using `pip`... ```bash $ pip install djangorestframework-xml ``` ## Example ```python REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( 'rest_framework_xml.parsers.XMLParser', ), 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework_xml.renderers.XMLRenderer', ), } ``` You can also set the renderer and parser used for an individual view, or viewset, using the APIView class based views. ```python from rest_framework import routers, serializers, viewsets from rest_framework_xml.parsers import XMLParser from rest_framework_xml.renderers import XMLRenderer class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email', 'is_staff') class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer parser_classes = (XMLParser,) renderer_classes = (XMLRenderer,) ``` ### Sample output ```xml http://127.0.0.1:8000/users/1/.xml jpadilla jpadilla@example.com True ``` ## Documentation & Support Full documentation for the project is available at [http://jpadilla.github.io/django-rest-framework-xml][docs]. You may also want to follow the [author][jpadilla] on Twitter. [build-status-image]: https://github.com/jpadilla/django-rest-framework-xml/workflows/CI/badge.svg [github-action]: https://github.com/jpadilla/django-rest-framework-xml/actions?query=workflow%3ACI [pypi-version]: https://img.shields.io/pypi/v/djangorestframework-xml.svg [pypi]: https://pypi.python.org/pypi/djangorestframework-xml [defusedxml]: https://pypi.python.org/pypi/defusedxml [docs]: http://jpadilla.github.io/django-rest-framework-xml [jpadilla]: https://twitter.com/jpadilla_ jpadilla-django-rest-framework-xml-da33b6b/docs/000077500000000000000000000000001364471253000217215ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/docs/css/000077500000000000000000000000001364471253000225115ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/docs/css/extra.css000066400000000000000000000005701364471253000243500ustar00rootroot00000000000000body.homepage div.col-md-9 h1:first-of-type { text-align: center; font-size: 60px; font-weight: 300; margin-top: 0; } body.homepage div.col-md-9 p:first-of-type { text-align: center; } body.homepage .badges { text-align: right; } body.homepage .badges a { display: inline-block; } body.homepage .badges a img { padding: 0; margin: 0; } jpadilla-django-rest-framework-xml-da33b6b/docs/index.md000066400000000000000000000055271364471253000233630ustar00rootroot00000000000000
--- # REST Framework XML XML support for Django REST Framework --- ## Overview XML support extracted as a third party package directly from the official Django REST Framework implementation. It requires the [defusedxml][defusedxml] package only because it safeguards against some security issues that were discovered. **Note**: XML output provided is an ad-hoc format that isn't formally described. If you have specific XML requirements you'll need to write your own XML parsers/renderers in order to fully control the representation. ## Requirements * Python 3.5+ * Django 2.2+ * Django REST Framework 3.11+ ## Installation Install using `pip`... ```bash $ pip install djangorestframework-xml ``` ## Example ```python REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( 'rest_framework_xml.parsers.XMLParser', ), 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework_xml.renderers.XMLRenderer', ), } ``` You can also set the renderer and parser used for an individual view, or viewset, using the APIView class based views. ```python from rest_framework import routers, serializers, viewsets from rest_framework_xml.parsers import XMLParser from rest_framework_xml.renderers import XMLRenderer class UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email', 'is_staff') class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer parser_classes = (XMLParser,) renderer_classes = (XMLRenderer,) ``` ### Sample output ```xml http://127.0.0.1:8000/users/1/.xml jpadilla jpadilla@example.com True ``` ## Testing Install testing requirements. ```bash $ pip install -e '.[dev]' ``` Run with pytest. ```bash $ pytest ``` You can also use the excellent [tox](http://tox.readthedocs.org/en/latest/) testing tool to run the tests against all supported versions of Python and Django. Install tox globally, and then simply run: ```bash $ tox ``` ## Documentation To build the documentation, you'll need to install `mkdocs`. ```bash $ pip install mkdocs ``` To preview the documentation: ```bash $ mkdocs serve Running at: http://127.0.0.1:8000/ ``` To build the documentation: ```bash $ mkdocs build ``` [defusedxml]: https://pypi.python.org/pypi/defusedxml jpadilla-django-rest-framework-xml-da33b6b/docs/parsers.md000066400000000000000000000033651364471253000237310ustar00rootroot00000000000000# Parsers ## Setting the parsers The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `XML` content. REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( 'rest_framework_xml.parsers.XMLParser', ) } You can also set the parsers used for an individual view, or viewset, using the `APIView` class based views. from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_xml.parsers import XMLParser class ExampleView(APIView): """ A view that can accept POST requests with XML content. """ parser_classes = (XMLParser,) def post(self, request, format=None): return Response({'received data': request.DATA}) Or, if you're using the `@api_view` decorator with function based views. @api_view(['POST']) @parser_classes((XMLParser,)) def example_view(request, format=None): """ A view that can accept POST requests with XML content. """ return Response({'received data': request.DATA}) --- # API Reference ## XMLParser Parses REST framework's default style of `XML` request content. Note that the `XML` markup language is typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`. If you are considering using `XML` for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type. Requires the `defusedxml` package to be installed. **.media_type**: `application/xml` jpadilla-django-rest-framework-xml-da33b6b/docs/renderers.md000066400000000000000000000041271364471253000242400ustar00rootroot00000000000000# Renderers ## Setting the renderers The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `XML` as the main media type and also include the self describing API. REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework_xml.renderers.XMLRenderer', ) } You can also set the renderers used for an individual view, or viewset, using the `APIView` class based views. from django.contrib.auth.models import User from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_xml.renderers import XMLRenderer class UserCountView(APIView): """ A view that returns the count of active users in XML. """ renderer_classes = (XMLRenderer,) def get(self, request, format=None): user_count = User.objects.filter(active=True).count() content = {'user_count': user_count} return Response(content) Or, if you're using the `@api_view` decorator with function based views. @api_view(['GET']) @renderer_classes((XMLRenderer,)) def user_count_view(request, format=None): """ A view that returns the count of active users in XML. """ user_count = User.objects.filter(active=True).count() content = {'user_count': user_count} return Response(content) --- # API Reference ## XMLRenderer Renders REST framework's default style of `XML` response content. Note that the `XML` markup language is used typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`. If you are considering using `XML` for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type. **.media_type**: `application/xml` **.format**: `'.xml'` **.charset**: `utf-8` **item_tag_name**: `list-item` **.root_tag_name**: `root` jpadilla-django-rest-framework-xml-da33b6b/mkdocs.yml000066400000000000000000000002521364471253000227730ustar00rootroot00000000000000site_name: djangorestframework-xml site_description: XML support for Django REST Framework repo_url: https://github.com/jpadilla/django-rest-framework-xml site_dir: html jpadilla-django-rest-framework-xml-da33b6b/pyproject.toml000066400000000000000000000005551364471253000237120ustar00rootroot00000000000000[build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" [tool.black] line-length = 79 [tool.isort] atomic=true force_grid_wrap=0 include_trailing_comma=true lines_after_imports=2 lines_between_types=1 multi_line_output=3 use_parentheses=true combine_as_imports=true known_first_party="rest_framework_xml" known_third_party=[] jpadilla-django-rest-framework-xml-da33b6b/rest_framework_xml/000077500000000000000000000000001364471253000247035ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/rest_framework_xml/__init__.py000066400000000000000000000000261364471253000270120ustar00rootroot00000000000000__version__ = "2.0.0" jpadilla-django-rest-framework-xml-da33b6b/rest_framework_xml/compat.py000066400000000000000000000004121364471253000265350ustar00rootroot00000000000000""" The `compat` module provides support for backwards compatibility with older versions of django/python, and compatibility wrappers around optional packages. """ # flake8: noqa try: import defusedxml.ElementTree as etree except ImportError: etree = None jpadilla-django-rest-framework-xml-da33b6b/rest_framework_xml/parsers.py000066400000000000000000000043331364471253000267370ustar00rootroot00000000000000""" Provides XML parsing support. """ import datetime import decimal from django.conf import settings from rest_framework.exceptions import ParseError from rest_framework.parsers import BaseParser from .compat import etree class XMLParser(BaseParser): """ XML parser. """ media_type = "application/xml" def parse(self, stream, media_type=None, parser_context=None): """ Parses the incoming bytestream as XML and returns the resulting data. """ assert etree, "XMLParser requires defusedxml to be installed" parser_context = parser_context or {} encoding = parser_context.get("encoding", settings.DEFAULT_CHARSET) parser = etree.DefusedXMLParser(encoding=encoding) try: tree = etree.parse(stream, parser=parser, forbid_dtd=True) except (etree.ParseError, ValueError) as exc: raise ParseError("XML parse error - %s" % str(exc)) data = self._xml_convert(tree.getroot()) return data def _xml_convert(self, element): """ convert the xml `element` into the corresponding python object """ children = list(element) if len(children) == 0: return self._type_convert(element.text) else: # if the fist child tag is list-item means all children are list-item if children[0].tag == "list-item": data = [] for child in children: data.append(self._xml_convert(child)) else: data = {} for child in children: data[child.tag] = self._xml_convert(child) return data def _type_convert(self, value): """ Converts the value returned by the XMl parse into the equivalent Python type """ if value is None: return value try: return datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S") except ValueError: pass try: return int(value) except ValueError: pass try: return decimal.Decimal(value) except decimal.InvalidOperation: pass return value jpadilla-django-rest-framework-xml-da33b6b/rest_framework_xml/renderers.py000066400000000000000000000027711364471253000272550ustar00rootroot00000000000000""" Provides XML rendering support. """ from io import StringIO from django.utils.encoding import force_str from django.utils.xmlutils import SimplerXMLGenerator from rest_framework.renderers import BaseRenderer class XMLRenderer(BaseRenderer): """ Renderer which serializes to XML. """ media_type = "application/xml" format = "xml" charset = "utf-8" item_tag_name = "list-item" root_tag_name = "root" def render(self, data, accepted_media_type=None, renderer_context=None): """ Renders `data` into serialized XML. """ if data is None: return "" stream = StringIO() xml = SimplerXMLGenerator(stream, self.charset) xml.startDocument() xml.startElement(self.root_tag_name, {}) self._to_xml(xml, data) xml.endElement(self.root_tag_name) xml.endDocument() return stream.getvalue() def _to_xml(self, xml, data): if isinstance(data, (list, tuple)): for item in data: xml.startElement(self.item_tag_name, {}) self._to_xml(xml, item) xml.endElement(self.item_tag_name) elif isinstance(data, dict): for key, value in data.items(): xml.startElement(key, {}) self._to_xml(xml, value) xml.endElement(key) elif data is None: # Don't output any value pass else: xml.characters(force_str(data)) jpadilla-django-rest-framework-xml-da33b6b/setup.cfg000066400000000000000000000000261364471253000226100ustar00rootroot00000000000000[wheel] universal = 1 jpadilla-django-rest-framework-xml-da33b6b/setup.py000066400000000000000000000071601364471253000225070ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import os import re import sys from setuptools import setup from setuptools.command.test import test as TestCommand # This command has been borrowed from # https://github.com/getsentry/sentry/blob/master/setup.py class PyTest(TestCommand): def finalize_options(self): TestCommand.finalize_options(self) self.test_args = ["tests"] self.test_suite = True def run_tests(self): import pytest errno = pytest.main(self.test_args) sys.exit(errno) def read(f): return open(f, "r", encoding="utf-8").read() def get_version(package): """ Return package version as listed in `__version__` in `init.py`. """ init_py = open(os.path.join(package, "__init__.py")).read() return re.search( "^__version__ = ['\"]([^'\"]+)['\"]", init_py, re.MULTILINE ).group(1) def get_packages(package): """ Return root package and all sub-packages. """ return [ dirpath for dirpath, dirnames, filenames in os.walk(package) if os.path.exists(os.path.join(dirpath, "__init__.py")) ] def get_package_data(package): """ Return all files under the root package, that are not in a package themselves. """ walk = [ (dirpath.replace(package + os.sep, "", 1), filenames) for dirpath, dirnames, filenames in os.walk(package) if not os.path.exists(os.path.join(dirpath, "__init__.py")) ] filepaths = [] for base, filenames in walk: filepaths.extend( [os.path.join(base, filename) for filename in filenames] ) return {package: filepaths} name = "djangorestframework-xml" package = "rest_framework_xml" version = get_version(package) description = "XML support for Django REST Framework" url = "https://github.com/jpadilla/django-rest-framework-xml" author = "José Padilla" author_email = "hello@jpadilla.com" license = "BSD" install_requires = ["defusedxml>=0.6.0"] extras_requires = { "docs": ["mkdocs>=0.11.1"], "tests": [ "Django>=1.6", "djangorestframework>=2.4.3", "pytest-django", "pytest", "flake8", ], } extras_requires["dev"] = ( extras_requires["docs"] + extras_requires["tests"] + ["tox", "pre-commit"] ) if sys.argv[-1] == "publish": os.system("python setup.py sdist upload") os.system("python setup.py bdist_wheel upload") print("You probably want to also tag the version now:") print(" git tag -a {0} -m 'version {0}'".format(version)) print(" git push --tags") sys.exit() setup( name=name, version=version, url=url, license=license, description=description, long_description=read("README.md"), long_description_content_type="text/markdown", author=author, author_email=author_email, packages=get_packages(package), package_data=get_package_data(package), cmdclass={"test": PyTest}, install_requires=install_requires, extras_require=extras_requires, python_requires=">=3.5", classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Internet :: WWW/HTTP", ], ) jpadilla-django-rest-framework-xml-da33b6b/tests/000077500000000000000000000000001364471253000221335ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/tests/__init__.py000066400000000000000000000000001364471253000242320ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/tests/conftest.py000066400000000000000000000050651364471253000243400ustar00rootroot00000000000000def pytest_configure(): from django.conf import settings settings.configure( DEBUG_PROPAGATE_EXCEPTIONS=True, DATABASES={ "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:", } }, SITE_ID=1, SECRET_KEY="not very secret in tests", USE_I18N=True, USE_L10N=True, STATIC_URL="/static/", ROOT_URLCONF="tests.urls", TEMPLATE_LOADERS=( "django.template.loaders.filesystem.Loader", "django.template.loaders.app_directories.Loader", ), MIDDLEWARE_CLASSES=( "django.middleware.common.CommonMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", ), INSTALLED_APPS=( "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "django.contrib.messages", "django.contrib.staticfiles", "rest_framework", "rest_framework.authtoken", "tests", ), PASSWORD_HASHERS=( "django.contrib.auth.hashers.SHA1PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", "django.contrib.auth.hashers.BCryptPasswordHasher", "django.contrib.auth.hashers.MD5PasswordHasher", "django.contrib.auth.hashers.CryptPasswordHasher", ), ) try: import oauth_provider # NOQA import oauth2 # NOQA except ImportError: pass else: settings.INSTALLED_APPS += ("oauth_provider",) try: import provider # NOQA except ImportError: pass else: settings.INSTALLED_APPS += ( "provider", "provider.oauth2", ) # guardian is optional try: import guardian # NOQA except ImportError: pass else: settings.ANONYMOUS_USER_ID = -1 settings.AUTHENTICATION_BACKENDS = ( "django.contrib.auth.backends.ModelBackend", "guardian.backends.ObjectPermissionBackend", ) settings.INSTALLED_APPS += ("guardian",) try: import django django.setup() except AttributeError: pass jpadilla-django-rest-framework-xml-da33b6b/tests/models.py000066400000000000000000000000001364471253000237560ustar00rootroot00000000000000jpadilla-django-rest-framework-xml-da33b6b/tests/test_parsers.py000066400000000000000000000036531364471253000252320ustar00rootroot00000000000000# -*- coding: utf-8 -*- import datetime from io import StringIO from django.test import TestCase from django.test.utils import skipUnless from rest_framework_xml.compat import etree from rest_framework_xml.parsers import XMLParser class TestXMLParser(TestCase): def setUp(self): self._input = StringIO( '' "" "121.0" "dasd" "" "2011-12-25 12:45:00" "" ) self._data = { "field_a": 121, "field_b": "dasd", "field_c": None, "field_d": datetime.datetime(2011, 12, 25, 12, 45, 00), } self._complex_data_input = StringIO( '' "" "2011-12-25 12:45:00" "" "1first" "2second" "" "name" "" ) self._complex_data = { "creation_date": datetime.datetime(2011, 12, 25, 12, 45, 00), "name": "name", "sub_data_list": [ {"sub_id": 1, "sub_name": "first"}, {"sub_id": 2, "sub_name": "second"}, ], } @skipUnless(etree, "defusedxml not installed") def test_parse(self): parser = XMLParser() data = parser.parse(self._input) self.assertEqual(data, self._data) @skipUnless(etree, "defusedxml not installed") def test_complex_data_parse(self): parser = XMLParser() data = parser.parse(self._complex_data_input) self.assertEqual(data, self._complex_data) jpadilla-django-rest-framework-xml-da33b6b/tests/test_renderers.py000066400000000000000000000100051364471253000255310ustar00rootroot00000000000000# -*- coding: utf-8 -*- import datetime from decimal import Decimal from io import StringIO from django.test import TestCase from django.test.utils import skipUnless from django.utils.translation import gettext_lazy from rest_framework_xml.compat import etree from rest_framework_xml.parsers import XMLParser from rest_framework_xml.renderers import XMLRenderer class XMLRendererTestCase(TestCase): """ Tests specific to the XML Renderer """ _complex_data = { "creation_date": datetime.datetime(2011, 12, 25, 12, 45, 00), "name": "name", "sub_data_list": [ {"sub_id": 1, "sub_name": "first"}, {"sub_id": 2, "sub_name": "second"}, ], } def test_render_string(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render({"field": "astring"}, "application/xml") self.assertXMLContains(content, "astring") def test_render_integer(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render({"field": 111}, "application/xml") self.assertXMLContains(content, "111") def test_render_datetime(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render( {"field": datetime.datetime(2011, 12, 25, 12, 45, 00)}, "application/xml", ) self.assertXMLContains(content, "2011-12-25 12:45:00") def test_render_float(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render({"field": 123.4}, "application/xml") self.assertXMLContains(content, "123.4") def test_render_decimal(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render( {"field": Decimal("111.2")}, "application/xml" ) self.assertXMLContains(content, "111.2") def test_render_none(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render({"field": None}, "application/xml") self.assertXMLContains(content, "") def test_render_complex_data(self): """ Test XML rendering. """ renderer = XMLRenderer() content = renderer.render(self._complex_data, "application/xml") self.assertXMLContains(content, "first") self.assertXMLContains(content, "second") def test_render_list(self): renderer = XMLRenderer() content = renderer.render(self._complex_data, "application/xml") self.assertXMLContains(content, "") self.assertXMLContains(content, "") def test_render_lazy(self): renderer = XMLRenderer() lazy = gettext_lazy("hello") content = renderer.render({"field": lazy}, "application/xml") self.assertXMLContains(content, "hello") @skipUnless(etree, "defusedxml not installed") def test_render_and_parse_complex_data(self): """ Test XML rendering. """ renderer = XMLRenderer() content = StringIO( renderer.render(self._complex_data, "application/xml") ) parser = XMLParser() complex_data_out = parser.parse(content) error_msg = "complex data differs!IN:\n %s \n\n OUT:\n %s" % ( repr(self._complex_data), repr(complex_data_out), ) self.assertEqual(self._complex_data, complex_data_out, error_msg) def assertXMLContains(self, xml, string): self.assertTrue( xml.startswith('\n') ) self.assertTrue(xml.endswith("")) self.assertTrue(string in xml, "%r not in %r" % (string, xml)) jpadilla-django-rest-framework-xml-da33b6b/tox.ini000066400000000000000000000013441364471253000223060ustar00rootroot00000000000000[pytest] strict = true addopts = -ra testpaths = tests filterwarnings = once::Warning ignore:::pympler[.*] [gh-actions] python = 3.5: py35 3.6: py36 3.7: py37 3.8: py38, lint, docs [tox] envlist = lint {py35,py36,py37}-django2.2-drf3.11 {py36,py37,py38}-django3.0-drf3.11 docs isolated_build = True [testenv] commands = pytest {posargs} deps = django2.2: Django==2.2.* django3.0: Django==3.0.* drf3.11: djangorestframework==3.11.* pytest-django [testenv:lint] basepython = python3.8 extras = dev passenv = HOMEPATH # needed on Windows commands = pre-commit run --all-files [testenv:docs] basepython = python3.8 extras = docs commands = mkdocs build