changeset 13:940676a0de84

ERRORS and WARNINGS are now enums
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 07 Jul 2023 02:10:32 +0200
parents 8e0b60f868dd
children cfb97c7c9e5b
files data_schema/__init__.py tests/test_schema.py
diffstat 2 files changed, 241 insertions(+), 232 deletions(-) [+]
line wrap: on
line diff
--- a/data_schema/__init__.py	Fri Jul 07 01:32:49 2023 +0200
+++ b/data_schema/__init__.py	Fri Jul 07 02:10:32 2023 +0200
@@ -31,6 +31,7 @@
 import collections
 import copy
 import datetime
+import enum
 import re
 import urllib.parse
 
@@ -57,74 +58,82 @@
 }
 _name_to_level = {name: level for (level, name) in _level_to_name.items()}
 
-ERRORS = {
-    10000: NC_("schema-msg", "dict expected"),
-    10001: NC_("schema-msg", "list expected"),
-    10002: NC_("schema-msg", "string expected"),
-    10003: NC_("schema-msg", "dict key must be a string"),
-    10004: NC_("schema-msg", "additional key encountered"),
-    10005: NC_("schema-msg", "required key(s) missing"),
-    10006: NC_("schema-msg", "min string length encountered"),
-    10007: NC_("schema-msg", "max string length exceeded"),
-    10008: NC_("schema-msg", "string value does not match the required RE pattern"),
-    10009: NC_("schema-msg", "string value does not validate"),
-    10010: NC_("schema-msg", "validation error"),
-    10011: NC_("schema-msg", "None/Null object expected"),
-    10012: NC_("schema-msg", "min list length encountered"),
-    10013: NC_("schema-msg", "max list length exceeded"),
-    10014: NC_("schema-msg", "tuple expected"),
-    10015: NC_("schema-msg", "min tuple length encountered"),
-    10016: NC_("schema-msg", "max tuple length exceeded"),
-    10017: NC_("schema-msg", "additional items in tuple not allowed"),
-    10018: NC_("schema-msg", "object is not empty"),
-    10019: NC_("schema-msg", "more than one match in `one-of' detected"),
-    10020: NC_("schema-msg", "int expected"),
-    10021: NC_("schema-msg", "int value lower than minValue"),
-    10022: NC_("schema-msg", "int value greater than maxValue"),
-    10023: NC_("schema-msg", "float expected"),
-    10024: NC_("schema-msg", "float value lower than minValue"),
-    10025: NC_("schema-msg", "float value greater than maxValue"),
-    10026: NC_("schema-msg", "boolean value expected"),
-    10027: NC_("schema-msg", "boolean true expected"),
-    10028: NC_("schema-msg", "boolean false expected"),
-    10029: NC_("schema-msg", "`not' expected problems but got none"),
-    10030: NC_("schema-msg", "numeric type (int or float) expected"),
-    10031: NC_("schema-msg", "numeric value lower than minValue"),
-    10032: NC_("schema-msg", "numeric value greater than maxValue"),
-    10033: NC_("schema-msg", "a plain scalar value expected"),
-    10034: NC_("schema-msg", "dict key does not match required schema"),
-    10035: NC_("schema-msg", "binary data expected"),
-    10036: NC_("schema-msg", "length of binary data lower than minValue"),
-    10037: NC_("schema-msg", "length of binary data exceeds maxValue"),
-    10038: NC_("schema-msg", "a set is expected"),
-    10039: NC_("schema-msg", "length of set lower than minLength"),
-    10040: NC_("schema-msg", "length of set greater than maxLength"),
-    10041: NC_("schema-msg", "timestamp expected"),
-    10042: NC_("schema-msg", "value of timestamp does not validate"),
-    10043: NC_("schema-msg", "enumerated string value expected but not found"),
-    10044: NC_("schema-msg", "referenced object doest not exist"),
-    10045: NC_("schema-msg", "key is not contained in referenced object"),
-    10046: NC_("schema-msg", "referenced object is not a container"),
-    10047: NC_("schema-msg", "binary data does not match the required RE pattern"),
-    10048: NC_("schema-msg", "enumerated integer value expected but not found"),
-    10049: NC_("schema-msg", "enumerated number value expected but not found"),
-    10050: NC_("schema-msg", "min dict length encountered"),
-    10051: NC_("schema-msg", "max dict length exceeded"),
-    10052: NC_("schema-msg", "index constraint violated"),
-    10053: NC_("schema-msg", "`one-of' failed"),
-    10054: NC_("schema-msg", "failing `one-of' item"),
-    10055: NC_("schema-msg", "`any-of' failed"),
-    10056: NC_("schema-msg", "failing `any-of' item"),
-    10057: NC_("schema-msg", "`all-of' failed"),
-    10058: NC_("schema-msg", "failing `all-of' item"),
-}
 
-WARNINGS = {
-    80000: NC_("schema-msg", "duplicate dict key"),
-}
+@enum.unique
+class ERRORS(enum.Enum):
+    E10000 = NC_("schema-msg", "dict expected")
+    E10001 = NC_("schema-msg", "list expected")
+    E10002 = NC_("schema-msg", "string expected")
+    E10003 = NC_("schema-msg", "dict key must be a string")
+    E10004 = NC_("schema-msg", "additional key encountered")
+    E10005 = NC_("schema-msg", "required key(s) missing")
+    E10006 = NC_("schema-msg", "min string length encountered")
+    E10007 = NC_("schema-msg", "max string length exceeded")
+    E10008 = NC_("schema-msg", "string value does not match the required RE pattern")
+    E10009 = NC_("schema-msg", "string value does not validate")
+    E10010 = NC_("schema-msg", "validation error")
+    E10011 = NC_("schema-msg", "None/Null object expected")
+    E10012 = NC_("schema-msg", "min list length encountered")
+    E10013 = NC_("schema-msg", "max list length exceeded")
+    E10014 = NC_("schema-msg", "tuple expected")
+    E10015 = NC_("schema-msg", "min tuple length encountered")
+    E10016 = NC_("schema-msg", "max tuple length exceeded")
+    E10017 = NC_("schema-msg", "additional items in tuple not allowed")
+    E10018 = NC_("schema-msg", "object is not empty")
+    E10019 = NC_("schema-msg", "more than one match in `one-of' detected")
+    E10020 = NC_("schema-msg", "int expected")
+    E10021 = NC_("schema-msg", "int value lower than minValue")
+    E10022 = NC_("schema-msg", "int value greater than maxValue")
+    E10023 = NC_("schema-msg", "float expected")
+    E10024 = NC_("schema-msg", "float value lower than minValue")
+    E10025 = NC_("schema-msg", "float value greater than maxValue")
+    E10026 = NC_("schema-msg", "boolean value expected")
+    E10027 = NC_("schema-msg", "boolean true expected")
+    E10028 = NC_("schema-msg", "boolean false expected")
+    E10029 = NC_("schema-msg", "`not' expected problems but got none")
+    E10030 = NC_("schema-msg", "numeric type (int or float) expected")
+    E10031 = NC_("schema-msg", "numeric value lower than minValue")
+    E10032 = NC_("schema-msg", "numeric value greater than maxValue")
+    E10033 = NC_("schema-msg", "a plain scalar value expected")
+    E10034 = NC_("schema-msg", "dict key does not match required schema")
+    E10035 = NC_("schema-msg", "binary data expected")
+    E10036 = NC_("schema-msg", "length of binary data lower than minValue")
+    E10037 = NC_("schema-msg", "length of binary data exceeds maxValue")
+    E10038 = NC_("schema-msg", "a set is expected")
+    E10039 = NC_("schema-msg", "length of set lower than minLength")
+    E10040 = NC_("schema-msg", "length of set greater than maxLength")
+    E10041 = NC_("schema-msg", "timestamp expected")
+    E10042 = NC_("schema-msg", "value of timestamp does not validate")
+    E10043 = NC_("schema-msg", "enumerated string value expected but not found")
+    E10044 = NC_("schema-msg", "referenced object doest not exist")
+    E10045 = NC_("schema-msg", "key is not contained in referenced object")
+    E10046 = NC_("schema-msg", "referenced object is not a container")
+    E10047 = NC_("schema-msg", "binary data does not match the required RE pattern")
+    E10048 = NC_("schema-msg", "enumerated integer value expected but not found")
+    E10049 = NC_("schema-msg", "enumerated number value expected but not found")
+    E10050 = NC_("schema-msg", "min dict length encountered")
+    E10051 = NC_("schema-msg", "max dict length exceeded")
+    E10052 = NC_("schema-msg", "index constraint violated")
+    E10053 = NC_("schema-msg", "`one-of' failed")
+    E10054 = NC_("schema-msg", "failing `one-of' item")
+    E10055 = NC_("schema-msg", "`any-of' failed")
+    E10056 = NC_("schema-msg", "failing `any-of' item")
+    E10057 = NC_("schema-msg", "`all-of' failed")
+    E10058 = NC_("schema-msg", "failing `all-of' item")
 
-if not set(ERRORS.keys()).isdisjoint(set(WARNINGS.keys())):
-    raise ValueError("ERRORS and WARNINGS must be disjoint")
+
+@enum.unique
+class WARNINGS(enum.Enum):
+    W80000 = NC_("schema-msg", "duplicate dict key")
+
+
+# Check some invariants at import time
+for e in ERRORS.__members__:
+    assert e.startswith('E'), "ERROR code `{}' shall start with letter `E'".format(e)
+    assert 10000 <= int(e[1:], 10) < 80000, "Invalid ERROR code number in `{}'".format(e)
+for w in WARNINGS.__members__:
+    assert w.startswith('W'), "WARNING code `{}' must start with letter `W'".format(w)
+    assert 80000 <= int(w[1:], 10), "Invalid WARNING code number in `{}'".format(w)
 
 
 TYPE_RE = type(re.compile(r"\A.+\Z"))
@@ -151,12 +160,14 @@
 def problem_message(pr):
     if isinstance(pr, ValidationProblem):
         code = getattr(pr, "code", None)
-    else:
+    elif isinstance(pr, (ERRORS, WARNINGS)):
         code = pr
-    msg = ERRORS.get(code, None)
-    if msg is None:
-        msg = WARNINGS[code]
-    return msg
+    else:
+        if pr >= 80000:
+            code = WARNINGS["W" + str(pr)]
+        else:
+            code = ERRORS["E" + str(pr)]
+    return code.value
 
 
 class ValidationProblem(object):
@@ -645,24 +656,24 @@
         if idx == effective_index:
             break
     else:
-        yield ValidationProblem(code=10052, context=context)
+        yield ValidationProblem(code=ERRORS.E10052, context=context)
 
 
 def validate_dict(obj, schema, context):
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, dict):
-        yield ValidationProblem(code=10000, hint="got: {}".format(type(obj).__name__), context=context)
+        yield ValidationProblem(code=ERRORS.E10000, hint="got: {}".format(type(obj).__name__), context=context)
         return
     yield from _validate_index_constraint(obj, schema, context)
     minlen = schema.get("minLength", None)
     if minlen:
         if len(obj) < minlen:
-            yield ValidationProblem(code=10050, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10050, hint=obj, context=context)
     maxlen = schema.get("maxLength", None)
     if maxlen is not None:
         if len(obj) > maxlen:
-            yield ValidationProblem(code=10051, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10051, hint=obj, context=context)
     schema_keys = schema.get("keys", {}) if schema else {}
     seen_keys = set()
     schema_keynames = schema.get_child("keyNames", None)
@@ -671,18 +682,18 @@
         idx += 1
         if schema_keynames is None:
             if not isinstance(key, str):
-                yield ValidationProblem(code=10003, hint=repr(key), context=context)
+                yield ValidationProblem(code=ERRORS.E10003, hint=repr(key), context=context)
         else:
             # validate the key against given schema
             new_context = Context(context, key=key, key_index=idx, current_object=key)
             key_probs = list(_validate(key, schema_keynames, new_context))
             if key_probs:
                 yield ValidationProblem(
-                    code=10034, hint=key, context=context, cause=key_probs)
+                    code=ERRORS.E10034, hint=key, context=context, cause=key_probs)
                 if context.settings.break_on_keynames_problems:
                     return
         if key in seen_keys:
-            yield ValidationProblem(code=80000, hint=key, context=context)
+            yield ValidationProblem(code=WARNINGS.W80000, hint=key, context=context)
         else:
             seen_keys.add(key)
         # XXX FIXME: context: new leaf context with new key for recursion
@@ -695,7 +706,7 @@
             if isinstance(additional_keys, bool):
                 if not additional_keys:
                     if not _is_in_skip_keys(key, context.settings.skip_keys):
-                        yield ValidationProblem(code=10004, hint=str(key), context=context)
+                        yield ValidationProblem(code=ERRORS.E10004, hint=str(key), context=context)
             else:
                 if not _is_in_skip_keys(key, context.settings.skip_keys):
                     # try this as the common schema for all the additional keys
@@ -708,24 +719,24 @@
         raise SchemaError("`required` must be an iterable")
     if not required_keys <= seen_keys:
         hs = [str(i) for i in required_keys - seen_keys]
-        yield ValidationProblem(code=10005, hint=sorted(hs), context=context)
+        yield ValidationProblem(code=ERRORS.E10005, hint=sorted(hs), context=context)
 
 
 def validate_list(obj, schema, context):
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, (list, tuple)):
-        yield ValidationProblem(code=10001, hint="got: {}".format(type(obj).__name__), context=context)
+        yield ValidationProblem(code=ERRORS.E10001, hint="got: {}".format(type(obj).__name__), context=context)
         return
     yield from _validate_index_constraint(obj, schema, context)
     minlen = schema.get("minLength", None)
     if minlen:
         if len(obj) < minlen:
-            yield ValidationProblem(code=10012, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10012, hint=obj, context=context)
     maxlen = schema.get("maxLength", None)
     if maxlen is not None:
         if len(obj) > maxlen:
-            yield ValidationProblem(code=10013, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10013, hint=obj, context=context)
     try:
         schema_items = schema.ensure_child_schema(schema["items"])
     except KeyError:
@@ -739,17 +750,17 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, (set, frozenset)):
-        yield ValidationProblem(code=10038, hint="got: {}".format(type(obj).__name__), context=context)
+        yield ValidationProblem(code=ERRORS.E10038, hint="got: {}".format(type(obj).__name__), context=context)
         return
     yield from _validate_index_constraint(obj, schema, context)
     minlen = schema.get("minLength", None)
     if minlen:
         if len(obj) < minlen:
-            yield ValidationProblem(code=10039, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10039, hint=obj, context=context)
     maxlen = schema.get("maxLength", None)
     if maxlen is not None:
         if len(obj) > maxlen:
-            yield ValidationProblem(code=10040, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10040, hint=obj, context=context)
     try:
         schema_items = schema.ensure_child_schema(schema["items"])
     except KeyError:
@@ -763,17 +774,17 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, (list, tuple)):
-        yield ValidationProblem(code=10014, hint="got: {}".format(type(obj).__name__), context=context)
+        yield ValidationProblem(code=ERRORS.E10014, hint="got: {}".format(type(obj).__name__), context=context)
         return
     yield from _validate_index_constraint(obj, schema, context)
     minlen = schema.get("minLength", None)
     if minlen:
         if len(obj) < minlen:
-            yield ValidationProblem(code=10015, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10015, hint=obj, context=context)
     maxlen = schema.get("maxLength", None)
     if maxlen is not None:
         if len(obj) > maxlen:
-            yield ValidationProblem(code=10016, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10016, hint=obj, context=context)
     schema_items = schema.get("items", [])
     if not isinstance(schema_items, (list, tuple)):
         raise SchemaError("tuple items require a list of schemata in items")
@@ -788,7 +799,7 @@
             additional_items = schema.get_child("additionalItems", False)
             if isinstance(additional_items, bool):
                 if not additional_items:
-                    yield ValidationProblem(code=10017, context=new_context)
+                    yield ValidationProblem(code=ERRORS.E10017, context=new_context)
             else:
                 yield from _validate(o, additional_items, new_context)
         else:
@@ -799,7 +810,7 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, str):
-        yield ValidationProblem(code=10002, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10002, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         enumvalues = schema.get("enum", None)
@@ -808,25 +819,25 @@
                 if ev == obj:
                     break
             else:
-                yield ValidationProblem(code=10043, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10043, hint=obj, context=context)
         minlen = schema.get("minLength", None)
         if minlen:
             if len(obj) < minlen:
-                yield ValidationProblem(code=10006, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10006, hint=obj, context=context)
         maxlen = schema.get("maxLength", None)
         if maxlen is not None:
             if len(obj) > maxlen:
-                yield ValidationProblem(code=10007, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10007, hint=obj, context=context)
         pattern = schema.get("pattern", None)
         if pattern is not None:
             if isinstance(pattern, str):
                 mo = re.search(pattern, obj)
                 if not mo:
-                    yield ValidationProblem(code=10008, context=context)
+                    yield ValidationProblem(code=ERRORS.E10008, context=context)
             elif isinstance(pattern, TYPE_RE):
                 mo = pattern.search(obj)
                 if not mo:
-                    yield ValidationProblem(code=10008, context=context)
+                    yield ValidationProblem(code=ERRORS.E10008, context=context)
             elif callable(pattern):
                 yield from pattern(obj, schema, context)
             else:
@@ -838,28 +849,28 @@
                                        schema,
                                        default=_SENTINEL)
             if refobj is _SENTINEL:
-                yield ValidationProblem(code=10044, context=context)
+                yield ValidationProblem(code=ERRORS.E10044, context=context)
             else:
                 try:
                     if obj not in refobj:
-                        yield ValidationProblem(code=10045, context=context)
+                        yield ValidationProblem(code=ERRORS.E10045, context=context)
                 except TypeError:
-                    yield ValidationProblem(code=10046, context=context)
+                    yield ValidationProblem(code=ERRORS.E10046, context=context)
 
 
 def validate_binary(obj, schema, context):
     if not isinstance(obj, (bytes, bytearray)):
-        yield ValidationProblem(code=10035, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10035, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         minlen = schema.get("minLength", None)
         if minlen:
             if len(obj) < minlen:
-                yield ValidationProblem(code=10036, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10036, hint=obj, context=context)
         maxlen = schema.get("maxLength", None)
         if maxlen is not None:
             if len(obj) > maxlen:
-                yield ValidationProblem(code=10037, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10037, hint=obj, context=context)
         pattern = schema.get("pattern", None)
         if pattern is not None:
             if isinstance(pattern, (str, bytes, bytearray)):
@@ -876,11 +887,11 @@
                     bytes_pattern = pattern
                 mo = re.search(bytes_pattern, obj)
                 if not mo:
-                    yield ValidationProblem(code=10047, context=context)
+                    yield ValidationProblem(code=ERRORS.E10047, context=context)
             elif isinstance(pattern, TYPE_RE):
                 mo = pattern.search(obj)
                 if not mo:
-                    yield ValidationProblem(code=10047, context=context)
+                    yield ValidationProblem(code=ERRORS.E10047, context=context)
             elif callable(pattern):
                 yield from pattern(obj, schema, context)
             else:
@@ -889,7 +900,7 @@
 
 def validate_timestamp(obj, schema, context):
     if not isinstance(obj, datetime.datetime):
-        yield ValidationProblem(code=10041, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10041, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         value = schema.get("value", None)
@@ -904,22 +915,22 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, int):
-        yield ValidationProblem(code=10020, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10020, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         minValue = schema.get("minValue", None)
         if minValue is not None and obj < minValue:
-            yield ValidationProblem(code=10021, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10021, hint=obj, context=context)
         maxValue = schema.get("maxValue", None)
         if maxValue is not None and obj > maxValue:
-            yield ValidationProblem(code=10022, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10022, hint=obj, context=context)
         enumvalues = schema.get("enum", None)
         if enumvalues is not None:
             for ev in enumvalues:
                 if ev == obj:
                     break
             else:
-                yield ValidationProblem(code=10048, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10048, hint=obj, context=context)
         value = schema.get("value", None)
         if value is not None:
             if callable(value):
@@ -932,15 +943,15 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, float):
-        yield ValidationProblem(code=10023, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10023, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         minValue = schema.get("minValue", None)
         if minValue is not None and obj < minValue:
-            yield ValidationProblem(code=10024, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10024, hint=obj, context=context)
         maxValue = schema.get("maxValue", None)
         if maxValue is not None and obj > maxValue:
-            yield ValidationProblem(code=10025, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10025, hint=obj, context=context)
         value = schema.get("value", None)
         if value is not None:
             if callable(value):
@@ -953,26 +964,26 @@
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, (int, float)):
-        yield ValidationProblem(code=10030, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10030, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         minValue = schema.get("minValue", None)
         if minValue is not None and isinstance(obj, float):
             minValue *= 1.0
         if minValue is not None and obj < minValue:
-            yield ValidationProblem(code=10031, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10031, hint=obj, context=context)
         maxValue = schema.get("maxValue", None)
         if maxValue is not None and isinstance(obj, float):
             maxValue *= 1.0
         if maxValue is not None and obj > maxValue:
-            yield ValidationProblem(code=10032, hint=obj, context=context)
+            yield ValidationProblem(code=ERRORS.E10032, hint=obj, context=context)
         enumvalues = schema.get("enum", None)
         if enumvalues is not None:
             for ev in enumvalues:
                 if ev == obj:
                     break
             else:
-                yield ValidationProblem(code=10049, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10049, hint=obj, context=context)
         value = schema.get("value", None)
         if value is not None:
             if callable(value):
@@ -986,14 +997,14 @@
         return
     yield from _validate_index_constraint(obj, schema, context)
     if obj is None:
-        yield ValidationProblem(code=10033, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10033, hint=obj, context=context)
     if isinstance(obj, (dict, list, tuple, set, frozenset)):
-        yield ValidationProblem(code=10033, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10033, hint=obj, context=context)
 
 
 def validate_deny(obj, schema, context):
     yield from _validate_index_constraint(obj, schema, context)
-    yield ValidationProblem(code=10010, context=context)
+    yield ValidationProblem(code=ERRORS.E10010, context=context)
 
 
 def validate_accept(obj, schema, context):
@@ -1003,7 +1014,7 @@
 def validate_null(obj, schema, context):
     yield from _validate_index_constraint(obj, schema, context)
     if obj is not None:
-        yield ValidationProblem(code=10011, context=context)
+        yield ValidationProblem(code=ERRORS.E10011, context=context)
 
 
 def validate_empty(obj, schema, context):
@@ -1012,14 +1023,14 @@
         return
     if isinstance(obj, (dict, list, tuple, set, frozenset)) and not obj:
         return
-    yield ValidationProblem(10018, context=context)
+    yield ValidationProblem(ERRORS.E10018, context=context)
 
 
 def validate_bool(obj, schema, context):
     if _is_null_allowed_for_object(obj, schema, context):
         return
     if not isinstance(obj, bool):
-        yield ValidationProblem(code=10026, hint=obj, context=context)
+        yield ValidationProblem(code=ERRORS.E10026, hint=obj, context=context)
     else:
         yield from _validate_index_constraint(obj, schema, context)
         value = schema.get("value", None)
@@ -1027,9 +1038,9 @@
             if callable(value):
                 yield from value(obj, schema, context)
             elif value and not obj:
-                yield ValidationProblem(code=10027, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10027, hint=obj, context=context)
             elif not value and obj:
-                yield ValidationProblem(code=10028, hint=obj, context=context)
+                yield ValidationProblem(code=ERRORS.E10028, hint=obj, context=context)
 
 
 def validate_allOf(obj, schema, context):
@@ -1043,11 +1054,11 @@
             res.append((idx, tr, ))
     if res:
         yield ValidationProblem(
-            code=10057,
+            code=ERRORS.E10057,
             context=context,
             cause=[
                 ValidationProblem(
-                    code=10058,
+                    code=ERRORS.E10058,
                     context=context,
                     cause=tr,
                     index=idx) for (idx, tr) in res])
@@ -1068,11 +1079,11 @@
     # Ansonsten: alle Fehlschlaege protokollieren
     if res:
         yield ValidationProblem(
-            code=10055,
+            code=ERRORS.E10055,
             context=context,
             cause=[
                 ValidationProblem(
-                    code=10056,
+                    code=ERRORS.E10056,
                     context=context,
                     cause=tr) for tr in res])
 
@@ -1095,24 +1106,24 @@
         # Ansonsten: alle Fehlschlaege protokollieren
         if failed_res:
             yield ValidationProblem(
-                code=10053,
+                code=ERRORS.E10053,
                 context=context,
                 cause=[
                     ValidationProblem(
-                        code=10054,
+                        code=ERRORS.E10054,
                         context=context,
                         cause=tr,
                         index=idx) for (idx, tr) in failed_res])
     else:
         # Die Indizes der "zuvielen" in "hint" anzeigen
-        yield ValidationProblem(code=10019, hint=",".join([str(k) for k in success_res]))
+        yield ValidationProblem(code=ERRORS.E10019, hint=",".join([str(k) for k in success_res]))
 
 
 def validate_not(obj, schema, context):
     assert isinstance(schema, _Schema)
     res = list(_validate(obj, schema, context))
     if not res:
-        yield ValidationProblem(code=10029, hint=obj, context=context,
+        yield ValidationProblem(code=ERRORS.E10029, hint=obj, context=context,
                                 cause=res)
 
 
--- a/tests/test_schema.py	Fri Jul 07 01:32:49 2023 +0200
+++ b/tests/test_schema.py	Fri Jul 07 02:10:32 2023 +0200
@@ -10,6 +10,7 @@
 
 import data_schema
 import data_schema.util
+from data_schema import ERRORS, WARNINGS
 
 
 TYPE_RE = type(re.compile(r"\A.+\Z"))
@@ -1338,18 +1339,15 @@
             self.assertFalse(
                 "no SchemaError raised when a non-dict given as schema")
 
-    def test_problem_ctor_nonexisting_code(self):
-        self.assertRaises(ValueError, data_schema.ValidationProblem, code=2)
-
     def test_problem_ctor_no_code(self):
         self.assertRaises(TypeError, data_schema.ValidationProblem, code=None)
 
     def test_error_ctor(self):
-        v = data_schema.ValidationProblem(code=10000)
+        v = data_schema.ValidationProblem(code=ERRORS.E10000)
         self.assertEqual(data_schema.ERROR, v.severity)
 
     def test_warning_ctor(self):
-        v = data_schema.ValidationProblem(code=80000)
+        v = data_schema.ValidationProblem(code=WARNINGS.W80000)
         self.assertEqual(data_schema.WARNING, v.severity)
 
     def test_d1(self):
@@ -1359,7 +1357,7 @@
     def test_d1_not_nullable(self):
         x = list(data_schema.validate(None, {"type": "dict"}))
         self.assertEqual(1, len(x))
-        self.assertEqual(10000, x[0].code)
+        self.assertEqual(ERRORS.E10000, x[0].code)
 
     def test_d1_nullable(self):
         x = list(data_schema.validate(None, {"type": "dict",
@@ -1370,7 +1368,7 @@
         x = list(data_schema.validate([], {"type": "map"}))
         self.assertEqual(1, len(x))
         self.assertEqual(data_schema.ERROR, x[0].severity)
-        self.assertEqual(10000, x[0].code)
+        self.assertEqual(ERRORS.E10000, x[0].code)
 
     def test_d3(self):
         x = list(data_schema.validate(
@@ -1379,10 +1377,10 @@
              "required": ["key2"]}))
         self.assertEqual(2, len(x))
         self.assertEqual(data_schema.ERROR, x[0].severity)
-        self.assertEqual(10004, x[0].code)
+        self.assertEqual(ERRORS.E10004, x[0].code)
         self.assertEqual("key", x[0].hint)
         self.assertEqual(data_schema.ERROR, x[1].severity)
-        self.assertEqual(10005, x[1].code)
+        self.assertEqual(ERRORS.E10005, x[1].code)
         self.assertEqual(["key2"], x[1].hint)
 
     def test_d4(self):
@@ -1401,7 +1399,7 @@
             {"type": "dict",
              "additionalKeys": False}))
         self.assertEqual(1, len(x))
-        self.assertEqual(10004, x[0].code)
+        self.assertEqual(ERRORS.E10004, x[0].code)
         self.assertEqual("key", x[0].hint)
 
     def test_d5_2(self):
@@ -1429,7 +1427,7 @@
              "additionalKeys": False},
             skip_keys=[re.compile(r"\A__.+"), re.compile(r"\Akey\d+\Z")]))
         self.assertEqual(1, len(x))
-        self.assertEqual(10004, x[0].code)
+        self.assertEqual(ERRORS.E10004, x[0].code)
         self.assertEqual("key", x[0].hint)
 
     def test_d6(self):
@@ -1454,7 +1452,7 @@
              "additionalKeys": {
                  "type": "string"}}))
         self.assertEqual(1, len(x))
-        self.assertEqual(10002, x[0].code)
+        self.assertEqual(ERRORS.E10002, x[0].code)
         self.assertEqual(1234, x[0].hint)
 
     def test_d8_2(self):
@@ -1472,7 +1470,7 @@
             {"type": "dict",
              "additionalKeys": True}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10003, pr[0].code)
+        self.assertEqual(ERRORS.E10003, pr[0].code)
 
     def test_d10_int_dict_keys(self):
         pr = list(data_schema.validate(
@@ -1486,17 +1484,17 @@
 
     def test_error_message(self):
         self.assertEqual("dict expected",
-                         data_schema.problem_message(10000))
-        pr = data_schema.ValidationProblem(code=10000)
+                         data_schema.problem_message(ERRORS.E10000))
+        pr = data_schema.ValidationProblem(code=ERRORS.E10000)
         self.assertEqual("dict expected", data_schema.problem_message(pr))
 
         self.assertEqual("duplicate dict key",
-                         data_schema.problem_message(80000))
-        pr = data_schema.ValidationProblem(code=80000)
+                         data_schema.problem_message(WARNINGS.W80000))
+        pr = data_schema.ValidationProblem(code=WARNINGS.W80000)
         self.assertEqual("duplicate dict key",
                          data_schema.problem_message(pr))
 
-        self.assertRaises(KeyError, data_schema.problem_message, 1234)
+        self.assertRaises(KeyError, data_schema.problem_message, 12345)
 
     def test_str_enum(self):
         pr = list(data_schema.validate(
@@ -1517,7 +1515,7 @@
             {"type": "string",
              "enum": ["e1", "e2"]}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10043, pr[0].code)
+        self.assertEqual(ERRORS.E10043, pr[0].code)
 
     def test_str_minlen(self):
         pr = list(data_schema.validate(
@@ -1531,7 +1529,7 @@
             {"type": "string",
              "minLength": 1}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10006, pr[0].code)
+        self.assertEqual(ERRORS.E10006, pr[0].code)
 
         pr = list(data_schema.validate(
             "x",
@@ -1551,7 +1549,7 @@
             {"type": "string",
              "maxLength": 0}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10007, pr[0].code)
+        self.assertEqual(ERRORS.E10007, pr[0].code)
 
         pr = list(data_schema.validate(
             "x",
@@ -1564,12 +1562,12 @@
             {"type": "string",
              "maxLength": 1}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10002, pr[0].code)
+        self.assertEqual(ERRORS.E10002, pr[0].code)
 
     @staticmethod
     def _pattern_check_function(obj, schema, context=None):
         if obj == " 5   ":
-            yield data_schema.ValidationProblem(code=10009)
+            yield data_schema.ValidationProblem(code=ERRORS.E10009)
 
     def test_str_re(self):
         pr = list(data_schema.validate(
@@ -1577,14 +1575,14 @@
             {"type": "string",
              "pattern": r'\A[0-9]+\Z'}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10008, pr[0].code)
+        self.assertEqual(ERRORS.E10008, pr[0].code)
 
         pr = list(data_schema.validate(
             "123",
             {"type": "string",
              "pattern": re.compile(r'\A[a-z]+\Z')}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10008, pr[0].code)
+        self.assertEqual(ERRORS.E10008, pr[0].code)
 
         pr = list(data_schema.validate(
             "123",
@@ -1597,7 +1595,7 @@
             {"type": "string",
              "pattern": self._pattern_check_function}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10009, pr[0].code)
+        self.assertEqual(ERRORS.E10009, pr[0].code)
 
     def test_binary_basic(self):
         pr = list(data_schema.validate(
@@ -1610,12 +1608,12 @@
             "",
             {"type": "binary"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10035, pr[0].code)
+        self.assertEqual(ERRORS.E10035, pr[0].code)
 
     @staticmethod
     def _binary_pattern_check_function(obj, schema, context=None):
         if obj != b"\x00":
-            yield data_schema.ValidationProblem(code=10009)
+            yield data_schema.ValidationProblem(code=ERRORS.E10009)
 
     def test_binary_pattern_check(self):
         pr = list(data_schema.validate(
@@ -1629,7 +1627,7 @@
             {"type": "binary",
              "pattern": self._binary_pattern_check_function}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10009, pr[0].code)
+        self.assertEqual(ERRORS.E10009, pr[0].code)
 
     def test_binary_re_str_match(self):
         pr = list(data_schema.validate(
@@ -1651,7 +1649,7 @@
             {"type": "binary",
              "pattern": u"\\x01+"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10047, pr[0].code)
+        self.assertEqual(ERRORS.E10047, pr[0].code)
 
     def test_binary_re_bytes_mismatch(self):
         pr = list(data_schema.validate(
@@ -1659,7 +1657,7 @@
             {"type": "binary",
              "pattern": b"\x01+"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10047, pr[0].code)
+        self.assertEqual(ERRORS.E10047, pr[0].code)
 
     def test_binary_length(self):
         pr = list(data_schema.validate(
@@ -1667,19 +1665,19 @@
             {"type": "binary",
              "minLength": 1}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10036, pr[0].code)
+        self.assertEqual(ERRORS.E10036, pr[0].code)
 
         pr = list(data_schema.validate(
             b"1",
             {"type": "binary",
              "maxLength": 0}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10037, pr[0].code)
+        self.assertEqual(ERRORS.E10037, pr[0].code)
 
     def test_deny(self):
         pr = list(data_schema.validate("abc", {"type": "deny"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10010, pr[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].code)
 
     def test_accept(self):
         pr = list(data_schema.validate("abc", {"type": "accept"}))
@@ -1703,7 +1701,7 @@
 
         pr = list(data_schema.validate({}, {"type": None}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10011, pr[0].code)
+        self.assertEqual(ERRORS.E10011, pr[0].code)
 
     def test_l1(self):
         pr = list(data_schema.validate([], {"type": "list"}))
@@ -1715,7 +1713,7 @@
     def test_l1_not_nullable(self):
         pr = list(data_schema.validate(None, {"type": "list"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10001, pr[0].code)
+        self.assertEqual(ERRORS.E10001, pr[0].code)
 
     def test_l1_nullable(self):
         pr = list(data_schema.validate(
@@ -1726,7 +1724,7 @@
         pr = list(data_schema.validate(["a", "b", "c"], {"type": "list"}))
         self.assertEqual(3, len(pr))
         for i in range(0, 3):
-            self.assertEqual(10010, pr[i].code)
+            self.assertEqual(ERRORS.E10010, pr[i].code)
 
     def test_l3_schema_for_items(self):
         pr = list(data_schema.validate(
@@ -1745,7 +1743,7 @@
     def test_t1_not_nullable(self):
         pr = list(data_schema.validate(None, {"type": "tuple"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10014, pr[0].code)
+        self.assertEqual(ERRORS.E10014, pr[0].code)
 
     def test_t1_nullable(self):
         pr = list(data_schema.validate(
@@ -1771,7 +1769,7 @@
                  {"type": None},
                  {"type": "deny"}]}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10010, pr[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].code)
         self.assertEqual(2, pr[0].context.index)
 
     def test_t4(self):
@@ -1782,7 +1780,7 @@
                  {"type": "string"},
                  {"type": None}]}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10017, pr[0].code)
+        self.assertEqual(ERRORS.E10017, pr[0].code)
         self.assertEqual(2, pr[0].context.index)
 
     def test_t5(self):
@@ -1822,7 +1820,7 @@
                  "keys": {"key": {"type": "string"}}
              }}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10016, pr[0].code)
+        self.assertEqual(ERRORS.E10016, pr[0].code)
 
     def test_t8(self):
         # do not check anything that exceeds maxLength
@@ -1839,8 +1837,8 @@
                  "keys": {"key": {"type": "string"}}
              }}))
         self.assertEqual(2, len(pr))
-        self.assertEqual(10015, pr[0].code)
-        self.assertEqual(10016, pr[1].code)
+        self.assertEqual(ERRORS.E10015, pr[0].code)
+        self.assertEqual(ERRORS.E10016, pr[1].code)
 
     def test_set1(self):
         # do not check anything that exceeds maxLength
@@ -1860,7 +1858,7 @@
             None,
             {"type": "set"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10038, pr[0].code)
+        self.assertEqual(ERRORS.E10038, pr[0].code)
 
     def test_set1_nullable(self):
         # do not check anything that exceeds maxLength
@@ -1880,7 +1878,7 @@
                  {"type": None}]}}
              ))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10039, pr[0].code)
+        self.assertEqual(ERRORS.E10039, pr[0].code)
 
     def test_set3(self):
         # do not check anything that exceeds maxLength
@@ -1893,7 +1891,7 @@
                  {"type": None}]}}
              ))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10040, pr[0].code)
+        self.assertEqual(ERRORS.E10040, pr[0].code)
 
     def test_set4_itemschema(self):
         pr = list(data_schema.validate(
@@ -1906,14 +1904,14 @@
         codes = set([p.code for p in pr])
 
         self.assertEqual(1, len(pr))
-        self.assertEqual(10055, pr[0].code)
+        self.assertEqual(ERRORS.E10055, pr[0].code)
         self.assertEqual(2, len(pr[0].cause))
-        self.assertEqual(10056, pr[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[0].code)
         self.assertEqual(1, len(pr[0].cause[0].cause))
-        self.assertEqual(10002, pr[0].cause[0].cause[0].code)
-        self.assertEqual(10056, pr[0].cause[1].code)
+        self.assertEqual(ERRORS.E10002, pr[0].cause[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[1].code)
         self.assertEqual(1, len(pr[0].cause[1].cause))
-        self.assertEqual(10020, pr[0].cause[1].cause[0].code)
+        self.assertEqual(ERRORS.E10020, pr[0].cause[1].cause[0].code)
 
     def test_empty(self):
         pr = list(data_schema.validate(None, {"type": "empty"}))
@@ -1924,7 +1922,7 @@
 
         pr = list(data_schema.validate(["a"], {"type": "empty"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10018, pr[0].code)
+        self.assertEqual(ERRORS.E10018, pr[0].code)
 
         pr = list(data_schema.validate(tuple(), {"type": "empty"}))
         self.assertEqual(0, len(pr))
@@ -1937,18 +1935,18 @@
 
         pr = list(data_schema.validate(tuple(["a"]), {"type": "empty"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10018, pr[0].code)
+        self.assertEqual(ERRORS.E10018, pr[0].code)
 
         pr = list(data_schema.validate({}, {"type": "empty"}))
         self.assertEqual(0, len(pr))
 
         pr = list(data_schema.validate({"key": "value"}, {"type": "empty"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10018, pr[0].code)
+        self.assertEqual(ERRORS.E10018, pr[0].code)
 
         pr = list(data_schema.validate("", {"type": "empty"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10018, pr[0].code)
+        self.assertEqual(ERRORS.E10018, pr[0].code)
 
     def test_allOf(self):
         pr = list(data_schema.validate(
@@ -1971,11 +1969,11 @@
                 ]
             }}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10057, pr[0].code)
+        self.assertEqual(ERRORS.E10057, pr[0].code)
         self.assertEqual(1, len(pr[0].cause))
-        self.assertEqual(10058, pr[0].cause[0].code)
+        self.assertEqual(ERRORS.E10058, pr[0].cause[0].code)
         self.assertEqual(1, len(pr[0].cause[0].cause))
-        self.assertEqual(10010, pr[0].cause[0].cause[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].cause[0].cause[0].code)
 
     def test_anyOf(self):
         pr = list(data_schema.validate(
@@ -1997,14 +1995,14 @@
                 ]
             }}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10055, pr[0].code)
+        self.assertEqual(ERRORS.E10055, pr[0].code)
         self.assertEqual(2, len(pr[0].cause))
-        self.assertEqual(10056, pr[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[0].code)
         self.assertEqual(1, len(pr[0].cause[0].cause))
-        self.assertEqual(10002, pr[0].cause[0].cause[0].code)
-        self.assertEqual(10056, pr[0].cause[1].code)
+        self.assertEqual(ERRORS.E10002, pr[0].cause[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[1].code)
         self.assertEqual(1, len(pr[0].cause[1].cause))
-        self.assertEqual(10010, pr[0].cause[1].cause[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].cause[1].cause[0].code)
 
     def test_anyOf_with_list(self):
         pr = list(data_schema.validate(
@@ -2022,14 +2020,14 @@
                 {"type": "deny"},
             ]}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10055, pr[0].code)
+        self.assertEqual(ERRORS.E10055, pr[0].code)
         self.assertEqual(2, len(pr[0].cause))
-        self.assertEqual(10056, pr[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[0].code)
         self.assertEqual(1, len(pr[0].cause[0].cause))
-        self.assertEqual(10002, pr[0].cause[0].cause[0].code)
-        self.assertEqual(10056, pr[0].cause[1].code)
+        self.assertEqual(ERRORS.E10002, pr[0].cause[0].cause[0].code)
+        self.assertEqual(ERRORS.E10056, pr[0].cause[1].code)
         self.assertEqual(1, len(pr[0].cause[1].cause))
-        self.assertEqual(10010, pr[0].cause[1].cause[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].cause[1].cause[0].code)
 
     def test_oneOf(self):
         pr = list(data_schema.validate(
@@ -2052,14 +2050,14 @@
             }}))
 
         self.assertEqual(1, len(pr))
-        self.assertEqual(10053, pr[0].code)
+        self.assertEqual(ERRORS.E10053, pr[0].code)
         self.assertEqual(2, len(pr[0].cause))
-        self.assertEqual(10054, pr[0].cause[0].code)
+        self.assertEqual(ERRORS.E10054, pr[0].cause[0].code)
         self.assertEqual(1, len(pr[0].cause[0].cause))
-        self.assertEqual(10002, pr[0].cause[0].cause[0].code)
-        self.assertEqual(10054, pr[0].cause[1].code)
+        self.assertEqual(ERRORS.E10002, pr[0].cause[0].cause[0].code)
+        self.assertEqual(ERRORS.E10054, pr[0].cause[1].code)
         self.assertEqual(1, len(pr[0].cause[1].cause))
-        self.assertEqual(10010, pr[0].cause[1].cause[0].code)
+        self.assertEqual(ERRORS.E10010, pr[0].cause[1].cause[0].code)
 
         pr = list(data_schema.validate(
             None,
@@ -2072,7 +2070,7 @@
                 ]
             }}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10019, pr[0].code)
+        self.assertEqual(ERRORS.E10019, pr[0].code)
         self.assertEqual("2,3", pr[0].hint)
 
     def test_not(self):
@@ -2082,7 +2080,7 @@
                 "not": {
                     "type": "empty"}}}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10029, pr[0].code)
+        self.assertEqual(ERRORS.E10029, pr[0].code)
 
         pr = list(data_schema.validate(
             None,
@@ -2099,7 +2097,7 @@
                 "not": {
                     "type": "int"}}}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10029, pr[0].code)
+        self.assertEqual(ERRORS.E10029, pr[0].code)
 
         pr = list(data_schema.validate(
             1,
@@ -2123,7 +2121,7 @@
             {"not": {
                 "type": "empty"}}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10029, pr[0].code)
+        self.assertEqual(ERRORS.E10029, pr[0].code)
 
         pr = list(data_schema.validate(
             None,
@@ -2137,7 +2135,7 @@
             {"not": {
                 "type": "int"}}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10029, pr[0].code)
+        self.assertEqual(ERRORS.E10029, pr[0].code)
 
         pr = list(data_schema.validate(
             1,
@@ -2158,7 +2156,7 @@
 
         pr = list(data_schema.validate(1, {"type": "float"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10023, pr[0].code)
+        self.assertEqual(ERRORS.E10023, pr[0].code)
 
         pr = list(data_schema.validate(
             2,
@@ -2167,8 +2165,8 @@
              "maxValue": 1}))
 
         self.assertEqual(2, len(pr))
-        self.assertEqual(10021, pr[0].code)
-        self.assertEqual(10022, pr[1].code)
+        self.assertEqual(ERRORS.E10021, pr[0].code)
+        self.assertEqual(ERRORS.E10022, pr[1].code)
 
     def test_float(self):
         pr = list(data_schema.validate(1.8, {"type": "float"}))
@@ -2176,7 +2174,7 @@
 
         pr = list(data_schema.validate(1, {"type": "float"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10023, pr[0].code)
+        self.assertEqual(ERRORS.E10023, pr[0].code)
 
         pr = list(data_schema.validate(
             2.0,
@@ -2185,8 +2183,8 @@
              "maxValue": 1.9}))
 
         self.assertEqual(2, len(pr))
-        self.assertEqual(10024, pr[0].code)
-        self.assertEqual(10025, pr[1].code)
+        self.assertEqual(ERRORS.E10024, pr[0].code)
+        self.assertEqual(ERRORS.E10025, pr[1].code)
 
     def test_number(self):
         pr = list(data_schema.validate(1.8, {"type": "number"}))
@@ -2201,12 +2199,12 @@
              "maxValue": 1.3}))
 
         self.assertEqual(2, len(pr))
-        self.assertEqual(10031, pr[0].code)
-        self.assertEqual(10032, pr[1].code)
+        self.assertEqual(ERRORS.E10031, pr[0].code)
+        self.assertEqual(ERRORS.E10032, pr[1].code)
 
         pr = list(data_schema.validate({}, {"type": "number"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10030, pr[0].code)
+        self.assertEqual(ERRORS.E10030, pr[0].code)
 
     def test_bool(self):
         pr = list(data_schema.validate(True, {"type": "bool"}))
@@ -2219,7 +2217,7 @@
         pr = list(data_schema.validate(True, {"type": "boolean",
                                               "value": False}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10028, pr[0].code)
+        self.assertEqual(ERRORS.E10028, pr[0].code)
 
         pr = list(data_schema.validate(False, {"type": "boolean"}))
         self.assertEqual(0, len(pr))
@@ -2231,26 +2229,26 @@
         pr = list(data_schema.validate(False, {"type": "boolean",
                                                "value": True}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10027, pr[0].code)
+        self.assertEqual(ERRORS.E10027, pr[0].code)
 
     def test_bool_real(self):
         pr = list(data_schema.validate([1, 2], {"type": "bool"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10026, pr[0].code)
+        self.assertEqual(ERRORS.E10026, pr[0].code)
 
         pr = list(data_schema.validate([], {"type": "bool"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10026, pr[0].code)
+        self.assertEqual(ERRORS.E10026, pr[0].code)
 
         pr = list(data_schema.validate(None, {"type": "bool"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10026, pr[0].code)
+        self.assertEqual(ERRORS.E10026, pr[0].code)
 
     @staticmethod
     def _check_value_ts(obj, schema, context):
         if obj == datetime.datetime.fromtimestamp(0):
             yield data_schema.ValidationProblem(
-                code=10042, hint=obj, context=context)
+                code=ERRORS.E10042, hint=obj, context=context)
 
     def test_timestamp(self):
         pr = list(data_schema.validate(
@@ -2268,7 +2266,7 @@
             {"type": "datetime",
              "value": self._check_value_ts}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10042, pr[0].code)
+        self.assertEqual(ERRORS.E10042, pr[0].code)
 
     def test_scalar(self):
         pr = list(data_schema.validate(1, {"type": "scalar"}))
@@ -2286,27 +2284,27 @@
 
         pr = list(data_schema.validate(None, {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate({}, {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate([], {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate(tuple(), {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate(set(), {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate(frozenset(), {"type": "scalar"}))
         self.assertEqual(1, len(pr))
-        self.assertEqual(10033, pr[0].code)
+        self.assertEqual(ERRORS.E10033, pr[0].code)
 
         pr = list(data_schema.validate(
             None,