Skip to content

Commit 77a1086

Browse files
authored
Merge pull request #301 from cwacek/fix/297
Attempt to resolve #297
2 parents 3fdb280 + f2bca60 commit 77a1086

File tree

4 files changed

+3368
-26
lines changed

4 files changed

+3368
-26
lines changed

python_jsonschema_objects/__init__.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -217,14 +217,14 @@ def build_classes(
217217
A namespace containing all the generated classes
218218
219219
"""
220-
kw = {"strict": strict, "any_of": any_of}
221-
builder = classbuilder.ClassBuilder(self.resolver)
220+
opts = {"strict": strict, "any_of": any_of}
221+
builder = classbuilder.ClassBuilder(self.resolver, opts)
222222
for nm, defn in self.schema.get("definitions", {}).items():
223223
resolved = self.resolver.lookup("#/definitions/" + nm)
224224
uri = python_jsonschema_objects.util.resolve_ref_uri(
225225
self.resolver._base_uri, "#/definitions/" + nm
226226
)
227-
builder.construct(uri, resolved.contents, **kw)
227+
builder.construct(uri, resolved.contents)
228228

229229
if standardize_names:
230230
name_transform = lambda t: inflection.camelize(
@@ -236,7 +236,7 @@ def build_classes(
236236
nm = self.schema["title"] if "title" in self.schema else self.schema["$id"]
237237
nm = inflection.parameterize(str(nm), "_")
238238

239-
builder.construct(nm, self.schema, **kw)
239+
builder.construct(nm, self.schema)
240240
self._resolved = builder.resolved
241241

242242
classes = {}

python_jsonschema_objects/classbuilder.py

+34-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import collections.abc
2-
from urllib.parse import urldefrag, urljoin
2+
import typing
33
import copy
44
import itertools
55
import logging
@@ -452,11 +452,19 @@ def __call__(self, *a, **kw):
452452
)
453453

454454

455+
class ClassBuilderOptions(typing.TypedDict):
456+
strict: bool
457+
any_of: str
458+
459+
455460
class ClassBuilder(object):
456-
def __init__(self, resolver: referencing._core.Resolver):
461+
def __init__(
462+
self, resolver: referencing._core.Resolver, options: ClassBuilderOptions
463+
):
457464
self.resolver = resolver
458465
self.resolved = {}
459466
self.under_construction = set()
467+
self.options = options
460468

461469
def expand_references(self, source_uri, iterable):
462470
"""Give an iterable of jsonschema descriptors, expands any
@@ -494,7 +502,7 @@ def resolve_type(self, ref, source):
494502
)
495503
resolved = self.resolver.lookup(uri)
496504
if resolved.resolver != self.resolver:
497-
sub_cb = ClassBuilder(resolved.resolver)
505+
sub_cb = ClassBuilder(resolved.resolver, self.options)
498506
self.resolved[uri] = sub_cb.construct(
499507
uri, resolved.contents, (ProtocolBase,)
500508
)
@@ -505,34 +513,38 @@ def resolve_type(self, ref, source):
505513

506514
return self.resolved[uri]
507515

508-
def construct(self, uri, *args, **kw):
516+
def construct(
517+
self, uri: str, clsdata: typing.Mapping[str, any], parent=(ProtocolBase,)
518+
):
509519
"""Wrapper to debug things"""
510520
logger.debug(util.lazy_format("Constructing {0}", uri))
511-
if ("override" not in kw or kw["override"] is False) and uri in self.resolved:
521+
if uri in self.resolved:
512522
logger.debug(util.lazy_format("Using existing {0}", uri))
513523
assert self.resolved[uri] is not None
514524
return self.resolved[uri]
515525
else:
516-
ret = self._construct(uri, *args, **kw)
526+
ret = self._construct(uri, clsdata, parent=parent)
517527
logger.debug(util.lazy_format("Constructed {0}", ret))
518528

519529
return ret
520530

521-
def _construct(self, uri, clsdata, parent=(ProtocolBase,), **kw):
531+
def _construct(
532+
self, uri: str, clsdata: typing.Mapping[str, any], parent=(ProtocolBase,)
533+
):
522534
if "anyOf" in clsdata:
523-
if kw.get("any_of", None) is None:
535+
if self.options.get("any_of", None) is None:
524536
raise NotImplementedError(
525537
"anyOf is not supported as bare property (workarounds available by setting any_of flag)"
526538
)
527-
if kw["any_of"] == "use-first":
539+
if self.options["any_of"] == "use-first":
528540
# Patch so the first anyOf becomes a single oneOf
529541
clsdata["oneOf"] = [
530542
clsdata["anyOf"].pop(0),
531543
]
532544
del clsdata["anyOf"]
533545
else:
534546
raise NotImplementedError(
535-
f"anyOf workaround is not a recognized type (any_of = {kw['any_of']})"
547+
f"anyOf workaround is not a recognized type (any_of = {self.options['any_of']})"
536548
)
537549

538550
if "oneOf" in clsdata:
@@ -557,7 +569,7 @@ def _construct(self, uri, clsdata, parent=(ProtocolBase,), **kw):
557569
elif util.safe_issubclass(p, ProtocolBase):
558570
parents.append(p)
559571

560-
self.resolved[uri] = self._build_object(uri, clsdata, parents, **kw)
572+
self.resolved[uri] = self._build_object(uri, clsdata, parents)
561573
return self.resolved[uri]
562574

563575
elif "$ref" in clsdata:
@@ -611,7 +623,7 @@ def _construct(self, uri, clsdata, parent=(ProtocolBase,), **kw):
611623
or clsdata.get("properties", None) is not None
612624
or clsdata.get("additionalProperties", False)
613625
):
614-
self.resolved[uri] = self._build_object(uri, clsdata, parent, **kw)
626+
self.resolved[uri] = self._build_object(uri, clsdata, parent)
615627
return self.resolved[uri]
616628
elif clsdata.get("type") in ("integer", "number", "string", "boolean", "null"):
617629
self.resolved[uri] = self._build_literal(uri, clsdata)
@@ -654,7 +666,7 @@ def _build_literal(self, nm, clsdata):
654666
"default",
655667
"asldkfn24olkjalskdfn e;laishd;1loj;flkansd;iow;naosdinfe;lkamjsdfj",
656668
)
657-
is not "asldkfn24olkjalskdfn e;laishd;1loj;flkansd;iow;naosdinfe;lkamjsdfj"
669+
!= "asldkfn24olkjalskdfn e;laishd;1loj;flkansd;iow;naosdinfe;lkamjsdfj"
658670
else clsdata.get("const")
659671
),
660672
}
@@ -663,7 +675,7 @@ def _build_literal(self, nm, clsdata):
663675

664676
return cls
665677

666-
def _build_object(self, nm, clsdata, parents, **kw):
678+
def _build_object(self, nm, clsdata, parents):
667679
logger.debug(util.lazy_format("Building object {0}", nm))
668680

669681
# To support circular references, we tag objects that we're
@@ -713,7 +725,7 @@ def _build_object(self, nm, clsdata, parents, **kw):
713725

714726
if detail.get("type", None) == "object":
715727
uri = "{0}/{1}_{2}".format(nm, prop, "<anonymous>")
716-
self.resolved[uri] = self.construct(uri, detail, (ProtocolBase,), **kw)
728+
self.resolved[uri] = self.construct(uri, detail, (ProtocolBase,))
717729

718730
props[prop] = make_property(
719731
prop, {"type": self.resolved[uri]}, self.resolved[uri].__doc__
@@ -741,7 +753,7 @@ def _build_object(self, nm, clsdata, parents, **kw):
741753
if "$ref" in detail["items"]:
742754
typ = self.resolve_type(detail["items"]["$ref"], nm)
743755
constraints = copy.copy(detail)
744-
constraints["strict"] = kw.get("strict")
756+
constraints["strict"] = self.options.get("strict")
745757
propdata = {
746758
"type": "array",
747759
"validator": wrapper_types.ArrayWrapper.create(
@@ -760,10 +772,10 @@ def _build_object(self, nm, clsdata, parents, **kw):
760772
)
761773
)
762774
else:
763-
typ = self.construct(uri, detail["items"], **kw)
775+
typ = self.construct(uri, detail["items"])
764776

765777
constraints = copy.copy(detail)
766-
constraints["strict"] = kw.get("strict")
778+
constraints["strict"] = self.options.get("strict")
767779
propdata = {
768780
"type": "array",
769781
"validator": wrapper_types.ArrayWrapper.create(
@@ -774,7 +786,7 @@ def _build_object(self, nm, clsdata, parents, **kw):
774786
except NotImplementedError:
775787
typ = detail["items"]
776788
constraints = copy.copy(detail)
777-
constraints["strict"] = kw.get("strict")
789+
constraints["strict"] = self.options.get("strict")
778790
propdata = {
779791
"type": "array",
780792
"validator": wrapper_types.ArrayWrapper.create(
@@ -787,15 +799,15 @@ def _build_object(self, nm, clsdata, parents, **kw):
787799
typs = []
788800
for i, elem in enumerate(detail["items"]):
789801
uri = "{0}/{1}/<anonymous_{2}>".format(nm, prop, i)
790-
typ = self.construct(uri, elem, **kw)
802+
typ = self.construct(uri, elem)
791803
typs.append(typ)
792804

793805
props[prop] = make_property(prop, {"type": typs})
794806

795807
else:
796808
desc = detail["description"] if "description" in detail else ""
797809
uri = "{0}/{1}".format(nm, prop)
798-
typ = self.construct(uri, detail, **kw)
810+
typ = self.construct(uri, detail)
799811

800812
props[prop] = make_property(prop, {"type": typ}, desc)
801813

@@ -821,7 +833,7 @@ def _build_object(self, nm, clsdata, parents, **kw):
821833

822834
props["__required__"] = required
823835
props["__has_default__"] = defaults
824-
if required and kw.get("strict"):
836+
if required and self.options.get("strict"):
825837
props["__strict__"] = True
826838

827839
props["__title__"] = clsdata.get("title")

0 commit comments

Comments
 (0)