<commit_before>#!/usr/bin/env python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-
#
# NetProfile: ExtDirect server
# © Copyright 2013-2016 Alex 'Unik' Unigovsky
#
# This file is part of NetProfile.
# NetProfile is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later
# version.
#
# NetProfile is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General
# Public License along with NetProfile. If not, see
# <http://www.gnu.org/licenses/>.
#
# Largely based on <NAME>'s pyramid_extdirect
# See http://github.com/jenner/pyramid_extdirect

from __future__ import (
	unicode_literals,
	print_function,
	absolute_import,
	division
)

from collections import defaultdict
import binascii
import json
import traceback
import datetime as dt
import decimal
from dateutil.tz import tzlocal

from pyramid.view import render_view_to_response
from webob import Response
from zope.interface import implementer
from zope.interface import Interface
from zope.interface.interfaces import ComponentLookupError
import venusian

from netprofile.ext.data import ExtModel
from netprofile.common.modules import IModuleManager
from netprofile.common.hooks import register_hook
from netprofile.common import ipaddr

# form parameters sent by ExtDirect when using a form-submit
# see http://www.sencha.com/products/js/direct.php
FORM_DATA_KEYS = frozenset([
	'extAction',
	'extMethod',
	'extTID',
	'extUpload',
	'extType'
])

# response to a file upload cannot be return as application/json, ExtDirect
# defines a special html response body for this use case where the response
# data is added to a textarea for faster JS-side decoding (since textarea text
# is not a DOM node)
FORM_SUBMIT_RESPONSE_TPL = '<html><body><textarea>%s</textarea></body></html>'

def get_ext_csrf(request):
	return request.headers.get('X-CSRFToken', '')

def _mk_cb_key(action_name, method_name):
	""" helper function to create a unique actions dict key """
	return action_name + '#' + method_name

class JsonReprEncoder(json.JSONEncoder):
	"""
	A convenience wrapper for classes that support __json__().
	"""
	def default(self, obj):
		if isinstance(obj, Response) and obj.content_type == 'application/json':
			# return decoded response body in case it's an already
			# rendered exception view
			return json.loads(obj.unicode_body)
		jr = getattr(obj, '__json__', None)
		if jr is not None:
			return jr()
		if isinstance(obj, dt.datetime):
			if obj.tzinfo is None:
				obj = obj.replace(tzinfo=tzlocal())
			return obj.isoformat()
		if isinstance(obj, dt.date):
			return obj.isoformat()
		if isinstance(obj, dt.time):
			return obj.isoformat()
		if isinstance(obj, ipaddr.IPv4Address):
			return int(obj)
		if isinstance(obj, ipaddr.IPv6Address):
			return tuple(obj.packed)
		if isinstance(obj, decimal.Decimal):
			return str(obj)
		if isinstance(obj, bytes):
			return binascii.hexlify(obj).decode()

		return super(JsonReprEncoder, self).default(obj)
<commit_msg>Add JSON serialization support for UUIDs<commit_after>#!/usr/bin/env python
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-
#
# NetProfile: ExtDirect server
# © Copyright 2013-2016 Alex 'Unik' Unigovsky
#
# This file is part of NetProfile.
# NetProfile is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public
# License as published by the Free Software Foundation, either
# version 3 of the License, or (at your option) any later
# version.
#
# NetProfile is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General
# Public License along with NetProfile. If not, see
# <http://www.gnu.org/licenses/>.
#
# Largely based on <NAME>'s pyramid_extdirect
# See http://github.com/jenner/pyramid_extdirect

from __future__ import (
	unicode_literals,
	print_function,
	absolute_import,
	division
)

from collections import defaultdict
import binascii
import json
import traceback
import datetime as dt
import decimal
import uuid
from dateutil.tz import tzlocal

from pyramid.view import render_view_to_response
from webob import Response
from zope.interface import implementer
from zope.interface import Interface
from zope.interface.interfaces import ComponentLookupError
import venusian

from netprofile.ext.data import ExtModel
from netprofile.common.modules import IModuleManager
from netprofile.common.hooks import register_hook
from netprofile.common import ipaddr

# form parameters sent by ExtDirect when using a form-submit
# see http://www.sencha.com/products/js/direct.php
FORM_DATA_KEYS = frozenset([
	'extAction',
	'extMethod',
	'extTID',
	'extUpload',
	'extType'
])

# response to a file upload cannot be return as application/json, ExtDirect
# defines a special html response body for this use case where the response
# data is added to a textarea for faster JS-side decoding (since textarea text
# is not a DOM node)
FORM_SUBMIT_RESPONSE_TPL = '<html><body><textarea>%s</textarea></body></html>'

def get_ext_csrf(request):
	return request.headers.get('X-CSRFToken', '')

def _mk_cb_key(action_name, method_name):
	""" helper function to create a unique actions dict key """
	return action_name + '#' + method_name

class JsonReprEncoder(json.JSONEncoder):
	"""
	A convenience wrapper for classes that support __json__().
	"""
	def default(self, obj):
		if isinstance(obj, Response) and obj.content_type == 'application/json':
			# return decoded response body in case it's an already
			# rendered exception view
			return json.loads(obj.unicode_body)
		jr = getattr(obj, '__json__', None)
		if jr is not None:
			return jr()
		if isinstance(obj, dt.datetime):
			if obj.tzinfo is None:
				obj = obj.replace(tzinfo=tzlocal())
			return obj.isoformat()
		if isinstance(obj, dt.date):
			return obj.isoformat()
		if isinstance(obj, dt.time):
			return obj.isoformat()
		if isinstance(obj, ipaddr.IPv4Address):
			return int(obj)
		if isinstance(obj, ipaddr.IPv6Address):
			return tuple(obj.packed)
		if isinstance(obj, decimal.Decimal):
			return str(obj)
		if isinstance(obj, bytes):
			return binascii.hexlify(obj).decode()
		if isinstance(obj, uuid.UUID):
			return str(obj)

		return super(JsonReprEncoder, self).default(obj)

{'fraction_non_alphanumeric': 0.0905877154220062, 'fraction_numerical': 0.003829724554426278, 'mean_word_length': 4.749364944961897, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4607861', 'n_tokens_mistral': 2143, 'n_tokens_neox': 2016, 'n_words': 740}