<commit_before># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, flt
import json

class ItemVariantExistsError(frappe.ValidationError): pass
class InvalidItemAttributeValueError(frappe.ValidationError): pass
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass

@frappe.whitelist()
def get_variant(template, args, variant=None):
	"""Validates Attributes and their Values, then looks for an exactly matching Item Variant

		:param item: Template Item
		:param args: A dictionary with "Attribute" as key and "Attribute Value" as value
	"""
	if isinstance(args, basestring):
		args = json.loads(args)

	if not args:
		frappe.throw(_("Please specify at least one attribute in the Attributes table"))

	return find_variant(template, args, variant)

def validate_item_variant_attributes(item, args=None):
	if isinstance(item, basestring):
		item = frappe.get_doc('Item', item)

	if not args:
		args = {d.attribute.lower():d.attribute_value for d in item.attributes}

	attribute_values, numeric_values = get_attribute_values()

	for attribute, value in args.items():
		if not value:
			continue

		if attribute.lower() in numeric_values:
			numeric_attribute = numeric_values[attribute.lower()]

			from_range = numeric_attribute.from_range
			to_range = numeric_attribute.to_range
			increment = numeric_attribute.increment

			if increment == 0:
				# defensive validation to prevent ZeroDivisionError
				frappe.throw(_("Increment for Attribute {0} cannot be 0").format(attribute))

			is_in_range = from_range <= flt(value) <= to_range
			precision = max(len(cstr(v).split(".")[-1].rstrip("0")) for v in (value, increment))
			#avoid precision error by rounding the remainder
			remainder = flt((flt(value) - from_range) % increment, precision)

			is_incremental = remainder==0 or remainder==increment

			if not (is_in_range and is_incremental):
				frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3} for Item {2}")\
					.format(attribute, from_range, to_range, increment, item.name), InvalidItemAttributeValueError)

		elif value not in attribute_values.get(attribute.lower(), []):
			frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values for Item {2}").format(
				value, attribute, item.name), InvalidItemAttributeValueError)

def get_attribute_values():
	if not frappe.flags.attribute_values:
		attribute_values = {}
		numeric_values = {}
		for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"]):
			attribute_values.setdefault(t.parent.lower(), []).append(t.attribute_value)

		for t in frappe.get_all('Item Attribute',
			fields=["name", "from_range", "to_range", "increment"], filters={'numeric_values': 1}):
			numeric_values[t.name.lower()] = t

		frappe.flags.attribute_values = attribute_values
		frappe.flags.numeric_values = numeric_values

	return frappe.flags.attribute_values, frappe.flags.numeric_values<commit_msg>[fix] variant error message<commit_after># Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cstr, flt
import json

class ItemVariantExistsError(frappe.ValidationError): pass
class InvalidItemAttributeValueError(frappe.ValidationError): pass
class ItemTemplateCannotHaveStock(frappe.ValidationError): pass

@frappe.whitelist()
def get_variant(template, args, variant=None):
	"""Validates Attributes and their Values, then looks for an exactly matching Item Variant

		:param item: Template Item
		:param args: A dictionary with "Attribute" as key and "Attribute Value" as value
	"""
	if isinstance(args, basestring):
		args = json.loads(args)

	if not args:
		frappe.throw(_("Please specify at least one attribute in the Attributes table"))

	return find_variant(template, args, variant)

def validate_item_variant_attributes(item, args=None):
	if isinstance(item, basestring):
		item = frappe.get_doc('Item', item)

	if not args:
		args = {d.attribute.lower():d.attribute_value for d in item.attributes}

	attribute_values, numeric_values = get_attribute_values()

	for attribute, value in args.items():
		if not value:
			continue

		if attribute.lower() in numeric_values:
			numeric_attribute = numeric_values[attribute.lower()]

			from_range = numeric_attribute.from_range
			to_range = numeric_attribute.to_range
			increment = numeric_attribute.increment

			if increment == 0:
				# defensive validation to prevent ZeroDivisionError
				frappe.throw(_("Increment for Attribute {0} cannot be 0").format(attribute))

			is_in_range = from_range <= flt(value) <= to_range
			precision = max(len(cstr(v).split(".")[-1].rstrip("0")) for v in (value, increment))
			#avoid precision error by rounding the remainder
			remainder = flt((flt(value) - from_range) % increment, precision)

			is_incremental = remainder==0 or remainder==increment

			if not (is_in_range and is_incremental):
				frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3} for Item {4}")\
					.format(attribute, from_range, to_range, increment, item.name),
					InvalidItemAttributeValueError, title=_('Invalid Attribute'))

		elif value not in attribute_values.get(attribute.lower(), []):
			frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values for Item {2}").format(
				value, attribute, item.name), InvalidItemAttributeValueError, title=_('Invalid Attribute'))

def get_attribute_values():
	if not frappe.flags.attribute_values:
		attribute_values = {}
		numeric_values = {}
		for t in frappe.get_all("Item Attribute Value", fields=["parent", "attribute_value"]):
			attribute_values.setdefault(t.parent.lower(), []).append(t.attribute_value)

		for t in frappe.get_all('Item Attribute',
			fields=["name", "from_range", "to_range", "increment"], filters={'numeric_values': 1}):
			numeric_values[t.name.lower()] = t

		frappe.flags.attribute_values = attribute_values
		frappe.flags.numeric_values = numeric_values

	return frappe.flags.attribute_values, frappe.flags.numeric_values
{'fraction_non_alphanumeric': 0.10692512115053932, 'fraction_numerical': 0.006252931061435048, 'mean_word_length': 5.353525322740814, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5268057', 'n_tokens_mistral': 2076, 'n_tokens_neox': 1910, 'n_words': 570}