Skip to content

Commit

Permalink
Merge branch 'fix-memory-issues' into fix-more-memory-issues
Browse files Browse the repository at this point in the history
  • Loading branch information
jesper-friis committed Nov 22, 2024
2 parents 1f432e4 + f2af32c commit 4863f88
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 207 deletions.
4 changes: 4 additions & 0 deletions bindings/python/dlite-collection.i
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ int dlite_collection_remove(struct _DLiteCollection *coll, const char *label);
struct _DLiteInstance *
dlite_collection_get_new(const struct _DLiteCollection *coll,
const char *label, const char *metaid);

// Although dlite_collection_get_id() returns a borrowed reference in C,
// we create a new object in Python that must be properly deallocated.
%newobject dlite_collection_get_id;
const struct _DLiteInstance *
dlite_collection_get_id(const struct _DLiteCollection *coll, const char *id);

int dlite_collection_has(const struct _DLiteCollection *coll,
const char *label);
int dlite_collection_has_id(const struct _DLiteCollection *coll,
Expand Down
18 changes: 18 additions & 0 deletions bindings/python/dlite-entity-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,26 @@ def get_instance(
metaid = str(metaid).rstrip("#/")
inst = _dlite.get_instance(id, metaid, check_storages)

if inst is None and id.startswith("http://onto-ns.com/"):
try:
import requests
except ModuleNotFoundError as e:
import warnings
warnings.warn(f"{e}: skip trying to fetch from entity service")
else:
import json
r = requests.get(id)
if r.ok:
d = json.loads(r.content.decode())
# Workaround for bugs in the entity service
if "meta" not in d or d["meta"] == dlite.ENTITY_SCHEMA:
if "dimensions" not in d:
d["dimensions"] = {}
inst = Instance.from_dict(d)

if inst is None:
raise _dlite.DLiteMissingInstanceError(f"no such instance: {id}")

return instance_cast(inst)

%}
Expand Down
14 changes: 12 additions & 2 deletions bindings/python/dlite-jstore-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ def format_dict(
return {uri if uri and urikey else uuid: dct}


class _JSONEncoder(json.JSONEncoder):
"""JSON encoder that also handle bytes object."""
def default(self, o):
if isinstance(o, bytes):
return "".join(f"{c:x}" for c in o)
elif (isinstance(o, (str, bool, int, float, list, dict)) or o is None):
return super().default(o)
else:
return str(o)
%}
Expand Down Expand Up @@ -203,7 +213,7 @@ def format_dict(
if "uuid" in d:
uuid = d["uuid"]
elif "uri" in d or "identity" in d:
uuid = _dlite.get_uuid(d.get("uri", d.get("identity")))
uuid = _dlite.get_uuid(str(d.get("uri", d.get("identity"))))
if id and uuid and _dlite.get_uuid(id) != uuid:
raise _dlite.DLiteInconsistentDataError(
Expand All @@ -223,7 +233,7 @@ def format_dict(
if id and id != uuid:
d.setdefault("uri", id)
self.load_json(json.dumps(d))
self.load_json(json.dumps(d, cls=_JSONEncoder))
def get_dict(self, id=None, soft7=True, single=None, with_uuid=None,
with_meta=False, with_parent=True, urikey=False):
Expand Down
6 changes: 3 additions & 3 deletions bindings/python/dlite-jstore.i
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
#include "dlite-errors.h"
#include "dlite-json.h"

/* If store `js` only has one instance, return its id, otherwise raise a
DLiteLookupError. */
/* If store `js` only has one instance, return borrowed reference to its id,
otherwise raise a DLiteLookupError. */
static const char *_single_id(JStore *js)
{
const char *key = jstore_get_single_key(js);
Expand Down Expand Up @@ -97,12 +97,12 @@ struct _JStore {};
%feature("docstring",
"If there is one instance in storage, return its id. "
"Otherwise, raise an DLiteLookupError exception.") get_single_id;
%newobject get_single_id;
const char *get_single_id(void) {
return _single_id($self);
}

%feature("docstring", "Iterate over all id's matching pattern.") get_ids;
%newobject get_ids;
struct _DLiteJStoreIter *get_ids(const char *pattern=NULL) {
return dlite_jstore_iter_create($self, pattern);
}
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/dlite-misc-python.i
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class errctl():
return [_dlite._err_getcode(errname) for errname in errnames]
silent = errctl(filename="None")
"""Context manager for a silent code block. Same as `errctl(filename="None")`."""
silent = errctl(hide=True)
"""Context manager for a silent code block. Same as `errctl(hide=True)`."""
# A set for keeping track of already issued deprecation warnings
_deprecation_warning_record = set()
Expand Down
1 change: 1 addition & 0 deletions bindings/python/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
],
},
}

inst = instance_from_dict(d)
print(inst)

Expand Down
174 changes: 26 additions & 148 deletions bindings/python/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,157 +160,35 @@ def add(self, d, id=None):
def instance_from_dict(d, id=None, single=None, check_storages=True):
"""Returns a new DLite instance created from dict.
Parameters
----------
d: dict
Dict to parse. It should be of the same form as returned
by the Instance.asdict() method.
id: str
Identity of the returned instance.
If `d` is in single-entity form with no explicit 'uuid' or
'uri', its identity will be assigned by `id`. Otherwise
`id` must be consistent with the 'uuid' and/or 'uri'
fields of `d`.
If `d` is in multi-entity form, `id` is used to select the
instance to return.
single: bool | None | "auto"
Whether the dict is assumed to be in single-entity form
If `single` is None or "auto", the form is inferred.
check_storages: bool
Whether to check if the instance already exists in storages
specified in `dlite.storage_path`.
Arguments:
d: Dict to parse. It should be of the same form as returned
by the Instance.asdict() method.
id: ID (URI or UUID) if instance to return.
single: Unsused. Provided for backward compabitility.
check_storages: bool
Whether to check if the instance already exists in storages
specified in `dlite.storage_path`.
"""
if single is None or single == "auto":
single = True if "properties" in d else False

if single:
if not id and "uuid" not in d and "uri" not in d:
if "namespace" in d and "version" in d and "name" in d:
id = f"{d['namespace']}/{d['version']}/{d['name']}"
else:
raise ValueError(
"`id` required for dicts in single-entry "
"form with no explicit uuid or uri."
)
else:
if not id:
if len(d) == 1:
(id,) = d.keys()
else:
raise ValueError(
"`id` required for dicts in multi-entry form."
)
if id in d:
return instance_from_dict(
d[id], id=id, single=True, check_storages=check_storages
)
else:
uuid = dlite.get_uuid(id)
if uuid in d:
return instance_from_dict(
d[uuid], id=id, single=True, check_storages=check_storages
)
else:
raise ValueError(f"no such id in dict: {id}")

if "uri" in d or "uuid" in d:
if "uri" in d and "uuid" in d:
if dlite.get_uuid(d["uri"]) != d["uuid"]:
raise dlite.DLiteError(
"uri and uuid in dict are not consistent"
)
uuid = dlite.get_uuid(str(d.get("uuid", d.get("uri"))))
if id:
if dlite.get_uuid(id) != uuid:
raise ValueError(
f"`id` is not consistent with uri/uuid in dict"
)

meta = dlite.get_instance(d.get("meta", dlite.ENTITY_SCHEMA))

if meta.is_metameta:
if "uri" in d:
uri = d["uri"]
elif "identity" in d:
uri = d["identity"]
elif "name" in d and "version" in d and "namespace" in d:
uri = dlite.join_meta_uri(d["name"], d["version"], d["namespace"])
elif id and dlite.urlparse(id).scheme:
uri = id
else:
raise TypeError(
"`id` required for metadata when the URI is not in the dict"
)

if check_storages:
try:
with dlite.silent:
return dlite.get_instance(uri)
except dlite.DLiteError:
pass

if "dimensions" not in d:
dimensions = []
elif isinstance(d["dimensions"], Sequence):
dimensions = [
dlite.Dimension(d["name"], d.get("description"))
for d in d["dimensions"]
]
elif isinstance(d["dimensions"], Mapping):
dimensions = [
dlite.Dimension(k, v) for k, v in d["dimensions"].items()
]
else:
raise TypeError(
"`dimensions` must be either a sequence or a mapping"
)

props = []
if isinstance(d["properties"], Sequence):
for p in d["properties"]:
props.append(
dlite.Property(
name=p["name"],
type=p["type"],
ref=p.get("$ref", p.get("ref")),
shape=p.get("shape", p.get("dims")),
unit=p.get("unit"),
description=p.get("description"),
)
)
elif isinstance(d["properties"], Mapping):
for k, v in d["properties"].items():
props.append(
dlite.Property(
name=k,
type=v["type"],
ref=v.get("$ref", v.get("ref")),
shape=v.get("shape", v.get("dims")),
unit=v.get("unit"),
description=v.get("description"),
)
)
else:
raise TypeError(
"`properties` must be either a sequence or a mapping"
)

inst = dlite.Instance.create_metadata(
uri, dimensions, props, d.get("description")
if single is not None:
dlite.deprecation_warning(
"0.7.0",
"Argument `single` is deprecated and not used. Single/multi-"
"instance format is now inferred.",
)
else:
dims = [
d["dimensions"][dim.name] for dim in meta.properties["dimensions"]
]
inst_id = d.get("uri", d.get("uuid", id))
inst = dlite.Instance.from_metaid(meta.uri, dimensions=dims, id=inst_id)
for p in meta["properties"]:
value = d["properties"][p.name]
inst.set_property(p.name, value)

return inst
js = dlite.JStore()
js.load_dict(d)

if check_storages:
if not id:
id = js.get_single_id()
try:
with dlite.silent:
return dlite.get_instance(id)
except dlite.DLiteMissingInstanceError:
pass

return js.get(id=id)


def to_metadata(obj):
Expand Down
9 changes: 3 additions & 6 deletions src/dlite-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ static DLiteInstance *parse_instance(const char *src, jsmntok_t *obj,
/* Parse dimensions */
if (dlite_meta_is_metameta(meta)) {
/* For metadata, dimension sizes are inferred from the size of
"dimensions", "propertis" and "relations". */
"dimensions", "properties" and "relations". */
size_t n=0;
if ((t = jsmn_item(src, obj, "dimensions"))) dims[n++] = t->size;
if ((t = jsmn_item(src, obj, "properties"))) dims[n++] = t->size;
Expand Down Expand Up @@ -722,11 +722,8 @@ static DLiteInstance *parse_instance(const char *src, jsmntok_t *obj,
if (dlite_property_jscan(src, t, NULL, ptr, p, pdims, 0) < 0)
goto fail;
} else if (t->type == JSMN_OBJECT) {
if (dlite_instance_is_meta(inst)) {
if (dlite_property_jscan(src, t, p->name, ptr, p, pdims, 0) < 0)
goto fail;
} else
FAIL1("missing key \"%s\" in JSON object", p->name);
if (dlite_property_jscan(src, t, p->name, ptr, p, pdims, 0) < 0)
goto fail;
} else {
if (dlite_type_scan(src+t->start, t->end - t->start, ptr, p->type,
p->size, 0) < 0)
Expand Down
24 changes: 0 additions & 24 deletions src/dlite-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,20 +445,12 @@ DLiteInstance *dlite_mapping_map(const DLiteMapping *m,
DLiteInstance *dlite_mapping(const char *output_uri,
const DLiteInstance **instances, int n)
{
//int i;
DLiteInstance *inst=NULL;
DLiteMapping *m=NULL;
Instances inputs;

map_init(&inputs);

int i;
printf("\n");
printf("<== dlite_mapping: in refcounts:\n");
for (i=0; i<n; i++)
printf(" - %s: refcount=%d\n",
instances[i]->uuid, instances[i]->_refcount);

/* Increases refcount on each input instance */
if (set_inputs(&inputs, instances, n)) goto fail;
if (!(m = mapping_create_base(output_uri, &inputs))) goto fail;
Expand All @@ -467,25 +459,9 @@ DLiteInstance *dlite_mapping(const char *output_uri,
fail:
if (m) dlite_mapping_free(m);

printf(" * inputs:\n");
map_iter_t iter = map_iter(&inputs);
const char *key;
while ((key = map_next(&inputs, &iter))) {
DLiteInstance *ins = *map_get(&inputs, key);
printf(" - %s: %s: refcount=%d\n", key, ins->uuid, ins->_refcount);
}

/* Decrease refcount */
// FIXME: Are all added refcounts removed again
//for (i=0; i<n; i++) dlite_instance_decref((DLiteInstance *)instances[i]);
decref_inputs(&inputs);
map_deinit(&inputs);

printf("==> dlite_mapping: out refcounts:\n");
for (i=0; i<n; i++)
printf(" - %s: refcount=%d\n",
instances[i]->uuid, instances[i]->_refcount);
printf(" inst (%s): refcount=%d\n", inst->uuid, inst->_refcount);

return inst;
}
Loading

0 comments on commit 4863f88

Please sign in to comment.