<commit_before>"""Various low level data validators."""

import os
import calendar


# -------
# Generic
# -------

def isDictEnough(value):
    """
    Some objects will likely come in that aren't
    dicts but are dict-ish enough.
    """
    if isinstance(value, dict):
        return True
    attrs = ("keys", "values", "items")
    for attr in attrs:
        if not hasattr(value, attr):
            return False
    return True

def genericTypeValidator(value, typ):
	"""
	Generic. (Added at version 2.)
	"""
	return isinstance(value, typ)

def genericIntListValidator(values, validValues):
	"""
	Generic. (Added at version 2.)
	"""
	if not isinstance(values, (list, tuple)):
		return False
	valuesSet = set(values)
	validValuesSet = set(validValues)
	if len(valuesSet - validValuesSet) > 0:
		return False
	for value in values:
		if not isinstance(value, int):
			return False
	return True

def genericNonNegativeIntValidator(value):
	"""
	Generic. (Added at version 3.)
	"""
	if not isinstance(value, int):
		return False
	if value < 0:
		return False
	return True

def genericNonNegativeNumberValidator(value):
	"""
	Generic. (Added at version 3.)
	"""
	if not isinstance(value, (int, float)):
		return False
	if value < 0:
		return False
	return True

def genericDictValidator(value, prototype):
	"""
	Generic. (Added at version 3.)
	"""
	# not a dict
	if not isinstance(value, dict):
		return False
	# missing required keys
	for key, (typ, required) in prototype.items():
		if not required:
			continue
		if key not in value:
			return False
	# unknown keys
	for key in value.keys():
		if key not in prototype:
			return False
	# incorrect types
	for key, v in value.items():
		prototypeType, required = prototype[key]
		if v is None and not required:
			continue
		if not isinstance(v, prototypeType):
			return False
	return True

# --------------
# fontinfo.plist
# --------------

# Data Validators

def fontInfoStyleMapStyleNameValidator(value):
	"""
	Version 2+.
	"""
	options = ["regular", "italic", "bold", "bold italic"]
	return value in options

def fontInfoOpenTypeGaspRangeRecordsValidator(value):
	"""
	Version 3+.
	"""
	if not isinstance(value, list):
		return False
	if len(value) == 0:
		return False
	validBehaviors = [0, 1, 2, 3]
	dictPrototype = dict(rangeMaxPPEM=(int, True), rangeGaspBehavior=(list, True))
	ppemOrder = []
	for rangeRecord in value:
		if not genericDictValidator(rangeRecord, dictPrototype):<commit_msg>Allow an empty list for the gasp records.<commit_after>"""Various low level data validators."""

import os
import calendar


# -------
# Generic
# -------

def isDictEnough(value):
    """
    Some objects will likely come in that aren't
    dicts but are dict-ish enough.
    """
    if isinstance(value, dict):
        return True
    attrs = ("keys", "values", "items")
    for attr in attrs:
        if not hasattr(value, attr):
            return False
    return True

def genericTypeValidator(value, typ):
	"""
	Generic. (Added at version 2.)
	"""
	return isinstance(value, typ)

def genericIntListValidator(values, validValues):
	"""
	Generic. (Added at version 2.)
	"""
	if not isinstance(values, (list, tuple)):
		return False
	valuesSet = set(values)
	validValuesSet = set(validValues)
	if len(valuesSet - validValuesSet) > 0:
		return False
	for value in values:
		if not isinstance(value, int):
			return False
	return True

def genericNonNegativeIntValidator(value):
	"""
	Generic. (Added at version 3.)
	"""
	if not isinstance(value, int):
		return False
	if value < 0:
		return False
	return True

def genericNonNegativeNumberValidator(value):
	"""
	Generic. (Added at version 3.)
	"""
	if not isinstance(value, (int, float)):
		return False
	if value < 0:
		return False
	return True

def genericDictValidator(value, prototype):
	"""
	Generic. (Added at version 3.)
	"""
	# not a dict
	if not isinstance(value, dict):
		return False
	# missing required keys
	for key, (typ, required) in prototype.items():
		if not required:
			continue
		if key not in value:
			return False
	# unknown keys
	for key in value.keys():
		if key not in prototype:
			return False
	# incorrect types
	for key, v in value.items():
		prototypeType, required = prototype[key]
		if v is None and not required:
			continue
		if not isinstance(v, prototypeType):
			return False
	return True

# --------------
# fontinfo.plist
# --------------

# Data Validators

def fontInfoStyleMapStyleNameValidator(value):
	"""
	Version 2+.
	"""
	options = ["regular", "italic", "bold", "bold italic"]
	return value in options

def fontInfoOpenTypeGaspRangeRecordsValidator(value):
	"""
	Version 3+.
	"""
	if not isinstance(value, list):
		return False
	if len(value) == 0:
		return True
	validBehaviors = [0, 1, 2, 3]
	dictPrototype = dict(rangeMaxPPEM=(int, True), rangeGaspBehavior=(list, True))
	ppemOrder = []
	for rangeRecord in value:
		if not genericDictValidator(rangeRecord, dictPrototype):
{'fraction_non_alphanumeric': 0.12553234638004462, 'fraction_numerical': 0.006083958629081322, 'mean_word_length': 3.495897903372835, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '3480481', 'n_tokens_mistral': 1617, 'n_tokens_neox': 1514, 'n_words': 530}