summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornitromaster101 <nitromaster101@5914aa95-5b3a-0410-a3b5-7b719e7fe9b2>2009-07-10 20:56:34 +0000
committernitromaster101 <nitromaster101@5914aa95-5b3a-0410-a3b5-7b719e7fe9b2>2009-07-10 20:56:34 +0000
commit2079cd7d198753caaa36dcb3adb44b4d94218d59 (patch)
treea0babc7684812d0b7b08c69bfb38f1efef1614e8
parentc2f3f59c07c6b9a35538c78d3d43b99a803bac72 (diff)
make freebase.schema more readable, moved some tests, finalizing the stuff that should actually be in the package
git-svn-id: http://freebase-python.googlecode.com/svn/trunk@178 5914aa95-5b3a-0410-a3b5-7b719e7fe9b2
-rw-r--r--freebase/api/session.py2
-rw-r--r--freebase/schema.py362
-rw-r--r--freebase/schema_cmd.py162
-rw-r--r--schema-manipulation/get_type.py448
-rw-r--r--schema-manipulation/type_creation.py470
-rw-r--r--test/runtests.py8
-rw-r--r--test/test_hardcore_schema_manipulation.py (renamed from schema-manipulation/test_hardcore_schema_manipulation.py)44
-rw-r--r--test/test_schema_manipulation.py12
8 files changed, 403 insertions, 1105 deletions
diff --git a/freebase/api/session.py b/freebase/api/session.py
index d717d53..ac3b5e4 100644
--- a/freebase/api/session.py
+++ b/freebase/api/session.py
@@ -39,7 +39,7 @@ declarations for external metaweb api.
__all__ = ['MetawebError', 'MetawebSession', 'HTTPMetawebSession', 'attrdict']
-__version__ = '0.5'
+__version__ = '1.0'
import os, sys, re
import cookielib
diff --git a/freebase/schema.py b/freebase/schema.py
index 62e5389..459c51a 100644
--- a/freebase/schema.py
+++ b/freebase/schema.py
@@ -2,6 +2,44 @@
from freebase.api.session import HTTPMetawebSession
from freebase.api.session import get_key_namespace, LITERAL_TYPE_IDS
+"""
+NOTE
+----
+graph is used freely in this file. Some information:
+ - It refers to an internal representation of a group of types.
+ - It resembles a mqlread result, but it is not a mqlread result
+ - It also has some helper variables like __requires and __related.
+ - It is produced by _get_graph
+ - It can be converted into valid json (json.dumps(graph, indent=2))
+
+Its structure is as follows:
+
+ "type_id" : {
+ "name" : "My Type",
+ "id" : "/base_id/type_id"
+ ...
+ "__requires" : ["/base_id/type_id2"]
+ "__properties" : [
+ {
+ "id" : "/base_id/type_id/my_prop"
+ ...
+ },
+ {
+ ...
+ }
+ ]
+ },
+ "type_id2" : {...}
+ ...
+
+"""
+
+class DelegationError(Exception):
+ """You can't set the expected_type if the expected_type of the delegated (master) is a primitive"""
+
+class CVTError(Exception):
+ """You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true."""
+
def key_exists(s, k):
q = {
"id" : k,
@@ -74,7 +112,7 @@ def get_property_info(s, prop_id):
elif res[i].has_key("value"):
info[i] = res[i]["value"]
else:
- raise Exception("There is a problem with getting the property value.")
+ raise ValueError("There is a problem with getting the property value.")
else: info[i] = None
# delete the properties that are going to be asked for in create_property
@@ -89,7 +127,7 @@ def get_property_info(s, prop_id):
# delete other useless things...
del res["id"]
- for i in [k for k, v in res.items() if v is None]:
+ for i in [k for k, v in res.iteritems() if v is None]:
del res[i]
info["__raw"] = res
@@ -97,9 +135,17 @@ def get_property_info(s, prop_id):
# Create Type
-def create_type(s, name, key, ns, cvt=None, tip=None, included=None, extra=None):
+def create_type(s, name, key, ns, cvt=False, tip=None, included=None, extra=None):
if key_exists(s, ns + "/" + key ):
return
+
+ # assert isinstance(name, basestring) # name could be mqlish
+ assert isinstance(key, basestring)
+ assert isinstance(ns, basestring)
+
+ assert tip is None or isinstance(tip, basestring)
+ assert included is None or isinstance(included, (basestring, list, tuple))
+ assert extra is None or isinstance(extra, dict)
q = {
"create" : "unconditional",
@@ -143,12 +189,17 @@ def create_type(s, name, key, ns, cvt=None, tip=None, included=None, extra=None)
# Create Property
def create_property(s, name, key, schema, expected, unique=False, disambig=False, tip=None, extra=None):
if key_exists(s, schema + "/" + key):
- # this isn't (neccesarily) a problem
- # raise Exception("The key \"%s\" already exists!" % (schema + "/" + key))
return
- # validate parameters str
-
+
+ # validate parameters
+ # assert isinstance(name, basestring) # could be mql
+ assert isinstance(key, basestring)
+ assert isinstance(schema, basestring)
+ assert isinstance(expected, basestring)
+ assert tip is None or isinstance(tip, basestring)
+ assert extra is None or isinstance(extra, dict)
+
q = {
"create" : "unconditional",
"type" : "/type/property",
@@ -169,10 +220,17 @@ def create_property(s, name, key, schema, expected, unique=False, disambig=False
q['/freebase/property_hints/disambiguator'] = { "connect" : "update", "value" : True }
if extra:
q.update(extra)
- #print json.dumps(q, indent=2)
return s.mqlwrite(q, use_permission_of=schema)
def delegate_property(s, p, schema, name=None, key=None, expected=None, tip=None, extra=None):
+
+ assert isinstance(p, basestring)
+ assert isinstance(schema, basestring)
+ #assert name is None or isinstance(name, basestring)
+ assert key is None or isinstance(key, basestring)
+ assert expected is None or isinstance(expected, basestring)
+ assert tip is None or isinstance(tip, basestring)
+
q = {
"id" : p,
"type" : "/type/property",
@@ -190,7 +248,7 @@ def delegate_property(s, p, schema, name=None, key=None, expected=None, tip=None
if r["expected_type"]["id"] in LITERAL_TYPE_IDS:
if expected:
if expected != r["expected_type"]["id"]:
- raise Exception("You can't set the expected_type if the expected_type of the delegated (master) is a primitive")
+ raise DelegationError("You can't set the expected_type if the expected_type of the delegated (master) is a primitive")
expected = r["expected_type"]["id"]
# If the expected_type of the delegator(master) is not a primitive, the delegated's
# expected_type can be different
@@ -233,6 +291,13 @@ def reciprocate_property(s, name, key, master, unique=False, disambig=False, tip
So, given a master, the reciprocal's schema is the master's expected type and the reciprocal's
expected type is the master's schema. """
+ # assert isinstance(name, basestring) # name could be mqlish
+ assert isinstance(key, basestring)
+ assert isinstance(master, basestring)
+
+ assert tip is None or isinstance(tip, basestring)
+ assert extra is None or isinstance(extra, dict)
+
q = {
"id" : master,
@@ -249,174 +314,126 @@ def reciprocate_property(s, name, key, master, unique=False, disambig=False, tip
return create_property(s, name, key, ect, schema, unique, disambig, tip,
extra = master)
-# upload / restore types
+# dump / restore types
def dump_base(s, base_id):
- types = map(lambda x: x["id"], s.mqlread({"id" : base_id, "/type/domain/types":[{"id" : None}]})["/type/domain/types"])
+ types = [type_object["id"] for type_object in s.mqlread({"id" : base_id, "/type/domain/types":[{"id" : None}]})["/type/domain/types"]]
graph = _get_graph(s, types, True)
- graph["__follow_types"] = True
-
+
return graph
def dump_type(s, type_id, follow_types=True):
types = [type_id]
graph = _get_graph(s, types, follow_types)
- graph["__follow_types"] = follow_types
return graph
-def restore(s, graph, new_location, ignore_types=None, debug=False):
+def restore(s, graph, new_location, ignore_types=None):
follow_types = graph.get("__follow_types", True)
- if debug: print "Following types:", follow_types
# create type dependencies
- typegraph = {}
- for tid, idres in graph.items():
- if not tid.startswith("__"):
- typegraph[tid] = idres["__requires"]
-
- type_deps = map(lambda (name, x): (len(x), name), typegraph.iteritems())
- type_deps.sort()
- if follow_types:
- types_to_create = create_what(type_deps, typegraph)
- else:
- types_to_create = typegraph.keys()
+ type_requires_graph = {}
- # create property dependencies
- propgraph = {}
- proptotype = {}
- for tid, idres in graph.items():
- if not tid.startswith("__"):
- for prop in idres["properties"]:
- propgraph[prop["id"]] = prop["__requires"]
- proptotype[prop["id"]] = tid
- prop_deps = map(lambda (name, x): (len(x), name), propgraph.items()) #*
- prop_deps.sort()
- if follow_types:
- props_to_create = create_what(prop_deps, propgraph)
- else:
- props_to_create = propgraph.keys()
+ # create prop dependencies
+ prop_requires_graph = {}
+ prop_to_type_map = {}
+
+ for type_id, type_information in graph.iteritems():
+ if not type_id.startswith("__"): # not a real type, but rather a helper
+ # type dependency generation
+ type_requires_graph[type_id] = type_information["__requires"]
+
+ # prop dependency generation
+ for prop in type_information["properties"]:
+ prop_requires_graph[prop["id"]] = prop["__requires"]
+ prop_to_type_map[prop["id"]] = type_id
+
- if debug: print "types", types_to_create
- if debug: print "-----------------------"
- if debug: print "props", props_to_create
- base_id, domain_id = s.mqlreadmulti([{"id" : types_to_create[0], "type" : "/type/type", "domain" : {"id" : None}},
- {"id" : new_location, "a:id" : None}])
- base_id = base_id["domain"]["id"]
- domain_id = domain_id["a:id"]
+ types_to_create = _generate_dependency_creation_order(type_requires_graph)
+ props_to_create = _generate_dependency_creation_order(prop_requires_graph)
+
+ origin_id, new_location_id = s.mqlreadmulti([{"id" : types_to_create[0], "type" : "/type/type", "domain" : {"id" : None}},
+ {"id" : new_location, "a:id" : None}])
+ origin_id = origin_id["domain"]["id"]
+ new_location_id = new_location_id["a:id"]
only_include = types_to_create + props_to_create
- for type in types_to_create:
- if debug: print type
- key = ""
- if len(graph[type]["key"]) == 1:
- key = graph[type]["key"][0]["value"]
- else:
- expectedname = graph[type]["id"].split("/")[-1]
- if base_id:
- for group in graph[type]["key"]:
- if group["namespace"] == base_id:
- key = group["value"]
- continue
- if key is None:
- key = expectedname
+ for type_id in types_to_create:
+ # let's find the type's key
+ key = None
+ for group in graph[type_id]["key"]:
+ if group["namespace"] == origin_id:
+ key = group["value"]
+ break
+
+ if key is None: # this shouldn't happen
+ key = graph[type_id]["id"].split("/")[-1] # this can be wrong... different key than typeid
+
+
tip = None
- if graph[type]["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]["value"]
+ if graph[type_id]["/freebase/documented_object/tip"]:
+ tip = graph[type_id]["/freebase/documented_object/tip"]["value"]
ignore = ("name", "domain", "key", "type", "id", "properties", "/freebase/type_hints/enumeration",
"/freebase/type_hints/included_types", "/freebase/type_hints/mediator", "/freebase/documented_object/tip")
- extra = {}
- for k, v in graph[type].items():
- if k not in ignore and not k.startswith("__"):
- if v:
- if isinstance(v, basestring):
- extra.update({k:v})
- elif isinstance(v, bool):
- extra.update({k:v})
- elif v.has_key("id"):
- extra.update({k:v["id"]})
- elif v.has_key("value"):
- extra.update({k:v["value"]})
- else:
- raise Exception("There is a problem with getting the property value.")
+ extra = _generate_extra_properties(graph[type_id], ignore)
- create_type(s, graph[type]["name"]["value"], key, domain_id,
- included=map(lambda x: convert_name(x["id"], base_id, domain_id, only_include), graph[type]["/freebase/type_hints/included_types"]),
- cvt=graph[type]["/freebase/type_hints/mediator"],
- tip=tip, extra=extra)
-
-
- if debug: print "--------------------------"
+ name = graph[type_id]["name"]["value"]
+ included = [_convert_name_to_new(included_type["id"], origin_id, new_location_id, only_include) for included_type in graph[type_id]["/freebase/type_hints/included_types"]]
+ cvt = graph[type_id]["/freebase/type_hints/mediator"]
+
+ create_type(s, name, key, new_location_id, included=included, cvt=cvt, tip=tip, extra=extra)
- for prop in props_to_create: #* prop_id
- info = graph[proptotype[prop]]["properties"]
- for i in info:
- if i["id"] == prop:
+ for prop_id in props_to_create: #* prop_id
+ type_id = prop_to_type_map[prop_id]
+ all_properties_for_type = graph[type_id]["properties"]
+ for prop in all_properties_for_type:
+ if prop["id"] == prop_id: # good, we are dealing with our specific property
+
+ new_schema = _convert_name_to_new(type_id, origin_id, new_location_id, only_include)
+
+ name = prop["name"]
- schema = convert_name(proptotype[prop], base_id, domain_id, only_include)
- if debug: print prop
expected = None
+ if prop["expected_type"]:
+ expected = _convert_name_to_new(prop["expected_type"], origin_id, new_location_id, only_include)
- if i["expected_type"]:
- expected = convert_name(i["expected_type"], base_id, domain_id, only_include)
- for k in i["key"]:
- if k["namespace"] == proptotype[prop]:
- key = k["value"]
- if i["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]
+ for group in prop["key"]:
+ if group["namespace"] == type_id:
+ key = group["value"]
+ break
+
+ tip = None
+ if prop["/freebase/documented_object/tip"]:
+ tip = prop["/freebase/documented_object/tip"]["value"]
- disambig = i["/freebase/property_hints/disambiguator"]
+ disambig = prop["/freebase/property_hints/disambiguator"]
+ unique = prop["unique"]
ignore = ("name", "expected_type", "key", "id", "master_property", "delegated", "unique", "type", "schema",
"/freebase/property_hints/disambiguator", "enumeration", "/freebase/property_hints/enumeration",
"/freebase/documented_object/tip")
- extra = {}
- for k, v in i.items():
- if k not in ignore and not k.startswith("__"):
- if v:
- if isinstance(v, basestring):
- extra.update({k:v})
- elif isinstance(v, bool):
- extra.update({k:v})
- elif v.has_key("id"):
- extra.update({k:v["id"]})
- elif v.has_key("value"):
- extra.update({k:v["value"]})
- else:
- raise Exception("There is a problem with getting the property value.")
-
- # since we are creating a property, all these connect insert delicacies are unneccesary
- """if isinstance(v, basestring) and v.startswith("/"): # an id
- extra.update({k : {"connect" : "insert", "id" : v}})
- elif isinstance(v, bool): # a bool value
- extra.update({k : {"connect" : "insert", "value" : v}})
- else: # an english value
- extra.update({k : {"connect" : "insert", "value" : v, "lang" : "/lang/en"}})"""
+ extra = _generate_extra_properties(prop, ignore)
- if i['master_property']:
- converted_master_property = convert_name(i["master_property"], base_id, domain_id, only_include)
- if converted_master_property == i["master_property"]:
- raise Exception("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
+ if prop['master_property']:
+ converted_master_property = _convert_name_to_new(prop["master_property"], origin_id, new_location_id, only_include)
+ if converted_master_property == prop["master_property"]:
+ raise CVTError("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
"The offending property was %s, whose master was %s." % (prop["id"], prop["master_property"]))
- reciprocate_property(s, i["name"], key, converted_master_property,
- i["unique"], disambig=disambig, tip=tip, extra=extra)
+ reciprocate_property(s, name, key, converted_master_property,
+ unique, disambig=disambig, tip=tip, extra=extra)
- elif i['delegated']:
- delegate_property(s, convert_name(i['delegated'], base_id, domain_id, only_include), schema,
+ elif prop['delegated']:
+ delegate_property(s, _convert_name_to_new(prop['delegated'], origin_id, new_location_id, only_include), new_schema,
expected=expected, tip=tip, extra=extra)
else:
- create_property(s, i["name"], key, schema, expected, i["unique"],
+ create_property(s, name, key, new_schema, expected, unique,
disambig=disambig, tip=tip, extra=extra)
-
-
-
-
def _get_graph(s, initial_types, follow_types):
""" get the graph of dependencies of all the types involved, starting with a list supplied """
@@ -434,40 +451,73 @@ def _get_graph(s, initial_types, follow_types):
done.update(graph[new]["__related"])
if not follow_types:
# we have to check that there are no cvts attached to us, or else
- # ugly things happen (we can't include the cvt)
+ # ugly things happen (we can't include the cvt because the cvt won't link to us.)
for prop in graph[new]["properties"]:
if prop["master_property"]:
- raise Exception("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
+ raise CVTError("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
"The offending property was %s, whose master was %s." % (prop["id"], prop["master_property"]))
+
+ graph["__follow_types"] = follow_types
return graph
-def convert_name(old_name, operating_base, new_base, only_include=None):
+def _convert_name_to_new(old_name, operating_base, new_base, only_include=None):
if old_name in only_include and old_name.startswith(operating_base):
return new_base + old_name.replace(operating_base, "", 1)
else:
return old_name
-def create_what(deps, graph):
- create_list = []
- while len(deps) > 0:
- neediness, id = deps.pop(0)
- if neediness == 0:
- create_list.append(id)
+def _generate_dependency_creation_order(requires_graph):
+ # This is a naive topographical sort to determine
+ # in what order to create types or properties so
+ # that the other type/properties they rely on
+ # are already created
+
+ # This function is called with the type dependencies
+ # and then the property dependencies.
+
+
+ # we sort the dependency_list because its a good idea
+ # to create the guys with zero dependencies before the
+ # guys with one.. it's just a simple optimization to
+ # the topographical sort
+ dependency_list = [(len(requires), name) for (name, requires) in requires_graph.iteritems()]
+ dependency_list.sort()
+
+ creation_order_list = []
+ while len(dependency_list) > 0:
+ number_of_requirements, id = dependency_list.pop(0)
+ if number_of_requirements == 0:
+ creation_order_list.append(id)
continue
else:
- work = True
- for req in graph[id]:
- if req not in create_list:
- work = False
+ are_the_types_dependencies_already_resolved = True
+ for requirement in requires_graph[id]:
+ if requirement not in creation_order_list:
+ are_the_types_dependencies_already_resolved = False
continue
- if work:
- create_list.append(id)
+ if are_the_types_dependencies_already_resolved:
+ creation_order_list.append(id)
else:
- deps.append((neediness, id))
- return create_list
-
+ dependency_list.append((number_of_requirements, id))
+ return creation_order_list
+def _generate_extra_properties(dictionary_of_values, ignore):
+ extra = {}
+ for k, v in dictionary_of_values.iteritems():
+ if k not in ignore and not k.startswith("__"):
+ if v:
+ if isinstance(v, basestring):
+ extra.update({k:v})
+ elif isinstance(v, bool):
+ extra.update({k:v})
+ elif v.has_key("id"):
+ extra.update({k:v["id"]})
+ elif v.has_key("value"):
+ extra.update({k:v["value"]})
+ else:
+ raise ValueError("There is a problem with getting the property value.")
+ return extra
def _get_needed(s, type_id):
q = TYPE_QUERY
@@ -491,8 +541,8 @@ def _get_needed(s, type_id):
# related can be used to generate subgraphs of types
# required is used to generate the dependency graph of types
- related = return_relevant(related_types, parents)
- requires = return_relevant(included_types, parents)
+ related = _return_relevant(related_types, parents)
+ requires = _return_relevant(included_types, parents)
# get property information
properties = r["properties"]
@@ -503,7 +553,7 @@ def _get_needed(s, type_id):
if prop["delegated"]:
dependent_on.add(prop["delegated"])
- prop["__requires"] = return_relevant(dependent_on, parents)
+ prop["__requires"] = _return_relevant(dependent_on, parents)
# return all the information along with our special __* properties
info = r
@@ -512,7 +562,7 @@ def _get_needed(s, type_id):
return info
-def return_relevant(start_list, parents):
+def _return_relevant(start_list, parents):
final = []
for item in start_list:
indomain = False
diff --git a/freebase/schema_cmd.py b/freebase/schema_cmd.py
new file mode 100644
index 0000000..a4644e8
--- /dev/null
+++ b/freebase/schema_cmd.py
@@ -0,0 +1,162 @@
+from optparse import OptionParser
+import getpass
+import sys
+
+from freebase.api import HTTPMetawebSession
+
+from freebase.schema import dump_base, dump_type, restore
+
+try:
+ import jsonlib2 as json
+except ImportError:
+ try:
+ import simplejson as json
+ except ImportError:
+ import json
+
+def fb_save_base():
+ op = OptionParser(usage='%prog [options] baseid')
+
+ op.disable_interspersed_args()
+
+ op.add_option('-s', '--service', dest='service_host',
+ metavar='HOST',
+ default="freebase.com",
+ help='Freebase HTTP service address:port')
+
+ op.add_option('-S', '--sandbox', dest='use_sandbox',
+ default=False, action='store_true',
+ help='shortcut for --service=sandbox-freebase.com')
+
+ options, args = op.parse_args()
+
+ service_host = options.service_host
+ if options.use_sandbox:
+ service_host = "sandbox-freebase.com"
+
+ if len(args) < 1:
+ op.error('Required baseid missing')
+
+ if len(args) > 1:
+ op.error('Too many arguments')
+
+ s = HTTPMetawebSession(service_host)
+
+ print json.dumps(dump_base(s, args[0]), indent=2)
+
+def fb_save_type():
+ op = OptionParser(usage='%prog [options] typeid ')
+
+ op.disable_interspersed_args()
+
+ op.add_option('-s', '--service', dest='service_host',
+ metavar='HOST',
+ default="freebase.com",
+ help='Freebase HTTP service address:port')
+
+ op.add_option('-S', '--sandbox', dest='use_sandbox',
+ default=False, action='store_true',
+ help='shortcut for --service=sandbox-freebase.com')
+
+ op.add_option('-n', '--no-follow', dest='follow',
+ default=False, action='store_false',
+ help="Don't follow types, only copy the one specified.")
+
+ op.add_option('-f', '--follow', dest="follow",
+ default=True, action="store_true",
+ help="Follow the types (you might end up copying multiple types)")
+
+
+ options,args = op.parse_args()
+
+ service_host = options.service_host
+ if options.use_sandbox:
+ service_host = "sandbox-freebase.com"
+
+ if len(args) < 1:
+ op.error('Required typeid missing')
+
+ if len(args) > 1:
+ op.error('Too many arguments')
+
+ s = HTTPMetawebSession(service_host)
+ print json.dumps(dump_type(s, args[0], options.follow), indent=2)
+
+
+def fb_restore():
+ op = OptionParser(usage='%prog [options] new_location graph_output_from_dump*_command')
+
+ op.disable_interspersed_args()
+
+ op.add_option('-s', '--service', dest='service_host',
+ metavar='HOST',
+ help='Freebase HTTP service address:port')
+
+ op.add_option('-S', '--sandbox', dest='use_sandbox',
+ default=False, action='store_true',
+ help='shortcut for --service=sandbox-freebase.com (default)')
+
+ op.add_option('-F', '--freebase', dest='use_freebase',
+ default=False, action='store_true',
+ help='shortcut for --service=freebase.com (not default)')
+
+ op.add_option('-u', '--username', dest='username',
+ action='store',
+ help='username for freebase service')
+
+ op.add_option('-p', '--password', dest='password',
+ action='store',
+ help='password for freebase service')
+
+
+
+ options,args = op.parse_args()
+
+ if (options.username and not options.password) or (not options.username and options.password):
+ op.error("You must supply both a username and password")
+
+ if options.use_sandbox and options.use_freebase:
+ op.error("You can't use both freebase and sandbox!")
+
+ if options.service_host and (options.use_sandbox or options.use_freebase):
+ op.error("You can't specify both --service and --freebase or --sandbox")
+
+ if not options.service_host and not options.use_sandbox and not options.use_freebase:
+ op.error("You have to specify to upload to sandbox or production (freebase)")
+
+ service_host = options.service_host
+ if options.use_sandbox:
+ service_host = "sandbox-freebase.com"
+ if options.use_freebase:
+ service_host = "freebase.com"
+
+ s = login(service_host, username=options.username, password=options.password)
+
+ newlocation = args[0]
+ if len(args) == 1:
+ graphfile = "-" #stdin
+ else: graphfile = args[1]
+ if graphfile != "-":
+ fg = open(graphfile, "r")
+ graph = json.load(fg)
+ fg.close()
+ if graphfile == "-": # use stdin
+ graph = json.load(sys.stdin)
+ print "loaded graph", graph
+ restore(s, graph, newlocation, ignore_types=None, debug=False)
+
+def login(api_host, username=None, password=None):
+
+ s = HTTPMetawebSession(api_host)
+ if not username:
+ print "In order to perform this operation, we need to use a valid freebase username and password"
+ username = raw_input("Please enter your username: ")
+ try:
+ password = getpass.getpass("Please enter your password: ")
+ except getpass.GetPassWarning:
+ password = raw_input("Please enter your password: ")
+
+ s.login(username, password)
+
+ print "Thanks!"
+ return s \ No newline at end of file
diff --git a/schema-manipulation/get_type.py b/schema-manipulation/get_type.py
deleted file mode 100644
index 80def68..0000000
--- a/schema-manipulation/get_type.py
+++ /dev/null
@@ -1,448 +0,0 @@
-# TODO: copy /freebase/type_hints junk
-# TODO: preserve property order.
-
-from pprint import pprint
-import random
-import json
-
-from freebase.schema import TYPE_QUERY, PROPERTY_QUERY
-from freebase.api import HTTPMetawebSession, MetawebError
-
-from freebase.schema import create_type, create_property, reciprocate_property, delegate_property
-
-s = HTTPMetawebSession("http://sandbox-freebase.com")
-s.login("nitromaster101@gmail.com", "something")
-
-import time
-
-def dump_base(s, base_id):
- types = map(lambda x: x["id"], s.mqlread({"id" : base_id, "/type/domain/types":[{"id" : None}]})["/type/domain/types"])
- graph = _get_graph(types)
- graph["__follow_types"] = True
-
- return graph
-
-def dump_type(s, type_id, follow_types=True):
- types = [type_id]
- graph = _get_graph(types, follow_types)
- graph["__follow_types"] = follow_types
- result = json.dumps(graph, indent=2)
-
- fh = open("junk.json", "w")
- fh.write(result)
- fh.close()
-
- return graph
-
-
-def upload_type(s, graph, new_location, ignore_types=None, debug=False):
- follow_types = graph.get("__follow_types", True)
- if debug: print "Following types:", follow_types
-
- # create type dependencies
- typegraph = {}
- for tid, idres in graph.items():
- if not tid.startswith("__"):
- typegraph[tid] = idres["__requires"]
-
- type_deps = map(lambda (name, x): (len(x), name), typegraph.items())
- type_deps.sort()
- if follow_types:
- types_to_create = create_what(type_deps, typegraph)
- else:
- types_to_create = typegraph.keys()
-
- # create property dependencies
- propgraph = {}
- proptotype = {}
- for tid, idres in graph.items():
- if not tid.startswith("__"):
- for prop in idres["properties"]:
- propgraph[prop["id"]] = prop["__requires"]
- proptotype[prop["id"]] = tid
- prop_deps = map(lambda (name, x): (len(x), name), propgraph.items())
- prop_deps.sort()
- if follow_types:
- props_to_create = create_what(prop_deps, propgraph)
- else:
- props_to_create = propgraph.keys()
-
- if debug: print "types", types_to_create
- if debug: print "-----------------------"
- if debug: print "props", props_to_create
-
- base_id, domain_id = s.mqlreadmulti([{"id" : types_to_create[0], "type" : "/type/type", "domain" : {"id" : None}},
- {"id" : new_location, "a:id" : None}])
- base_id = base_id["domain"]["id"]
- domain_id = domain_id["a:id"]
-
- only_include = types_to_create + props_to_create
-
- for type in types_to_create:
- if debug: print type
- key = ""
- if len(graph[type]["key"]) == 1:
- key = graph[type]["key"][0]["value"]
- else:
- expectedname = graph[type]["id"].split("/")[-1]
- if base_id:
- for group in graph[type]["key"]:
- if group["namespace"] == base_id:
- key = group["value"]
- continue
- if key is None:
- key = expectedname
- tip = None
- if graph[type]["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]["value"]
-
- ignore = ("name", "domain", "key", "type", "id", "properties", "/freebase/type_hints/enumeration",
- "/freebase/type_hints/included_types", "/freebase/type_hints/mediator", "/freebase/documented_object/tip")
- extra = {}
- for k, v in graph[type].items():
- if k not in ignore and not k.startswith("__"):
- if v:
- if isinstance(v, basestring):
- extra.update({k:v})
- elif isinstance(v, bool):
- extra.update({k:v})
- elif v.has_key("id"):
- extra.update({k:v["id"]})
- elif v.has_key("value"):
- extra.update({k:v["value"]})
- else:
- raise Exception("There is a problem with getting the property value.")
-
- create_type(s, graph[type]["name"]["value"], key, domain_id,
- included=map(lambda x: convert_name(x["id"], base_id, domain_id, only_include), graph[type]["/freebase/type_hints/included_types"]),
- cvt=graph[type]["/freebase/type_hints/mediator"],
- tip=tip, extra=extra)
-
-
- if debug: print "--------------------------"
-
- for prop in props_to_create:
- info = graph[proptotype[prop]]["properties"]
- for i in info:
- if i["id"] == prop:
-
- schema = convert_name(proptotype[prop], base_id, domain_id, only_include)
- if debug: print prop
- expected = None
-
- if i["expected_type"]:
- expected = convert_name(i["expected_type"], base_id, domain_id, only_include)
- for k in i["key"]:
- if k.namespace == proptotype[prop]:
- key = k.value
- if i["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]
-
- disambig = i["/freebase/property_hints/disambiguator"]
-
- ignore = ("name", "expected_type", "key", "id", "master_property", "delegated", "unique", "type", "schema",
- "/freebase/property_hints/disambiguator", "enumeration", "/freebase/property_hints/enumeration",
- "/freebase/documented_object/tip")
- extra = {}
- for k, v in i.items():
- if k not in ignore and not k.startswith("__"):
- if v:
- if isinstance(v, basestring):
- extra.update({k:v})
- elif isinstance(v, bool):
- extra.update({k:v})
- elif v.has_key("id"):
- extra.update({k:v["id"]})
- elif v.has_key("value"):
- extra.update({k:v["value"]})
- else:
- raise Exception("There is a problem with getting the property value.")
-
- # since we are creating a property, all these connect insert delicacies are unneccesary
- """if isinstance(v, basestring) and v.startswith("/"): # an id
- extra.update({k : {"connect" : "insert", "id" : v}})
- elif isinstance(v, bool): # a bool value
- extra.update({k : {"connect" : "insert", "value" : v}})
- else: # an english value
- extra.update({k : {"connect" : "insert", "value" : v, "lang" : "/lang/en"}})"""
-
-
- if i['master_property']:
- converted_master_property = convert_name(i["master_property"], base_id, domain_id, only_include)
- if converted_master_property == i["master_property"]:
- raise Exception("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
- "The offending property was %s, whose master was %s." % (prop["id"], prop["master_property"]))
- reciprocate_property(s, i["name"], key, converted_master_property,
- i["unique"], disambig=disambig, tip=tip, extra=extra)
-
- elif i['delegated']:
- delegate_property(s, convert_name(i['delegated'], base_id, domain_id, only_include), schema,
- expected=expected, tip=tip, extra=extra)
-
- else:
- create_property(s, i["name"], key, schema, expected, i["unique"],
- disambig=disambig, tip=tip, extra=extra)
-
-
-
-
-
-
-def _get_graph(initial_types, follow_types):
- """ get the graph of dependencies of all the types involved, starting with a list supplied """
-
- assert isinstance(initial_types, (list, tuple))
-
- graph = {}
- to_update = set(initial_types)
- done = set()
- while len(to_update) > 0:
- new = to_update.pop()
- graph[new] = _get_needed(s, new)
- if follow_types:
- [to_update.add(b) for b in graph[new]["__related"] if b not in done]
- done.update(graph[new]["__related"])
- if not follow_types:
- # we have to check that there are no cvts attached to us, or else
- # ugly things happen (we can't include the cvt)
- for prop in graph[new]["properties"]:
- if prop["master_property"]:
- raise Exception("You can't set follow_types to False if there's a cvt. A cvt requires you get all the relevant types. Set follow_types to true.\n" + \
- "The offending property was %s, whose master was %s." % (prop["id"], prop["master_property"]))
- return graph
-
-"""def create_type_dependencies(s, base_id=None, type_id=None, follow_types=True):
-
- if base_id:
- q = {"id" : base_id, "/type/domain/types" : [{"id" : None}] }
- results = s.mqlread(q)
- types = map(lambda x: x["id"], results["/type/domain/types"])
- #pprint(types)
-
- if type_id:
- types = [type_id]
- base_id = "/".join(type_id.split("/")[:-1])
- print base_id
-
- if not base_id and not type_id:
- raise Exception("You need to supply either a base_id or a type_id")
-
- graph = get_graph(types, follow_types)
-
- # find distinct subgraphs (looking at needs)
- subgraphs = []
- unknown = set(graph.keys())
- if focus:
- unknown = set([focus])
- while len(unknown) > 0:
- visited = set()
- to_visit = set([list(unknown)[0]])
- while len(to_visit) > 0:
- new = to_visit.pop()
- visited.add(new)
- try:
- unknown.remove(new)
- except KeyError:
- pass
- [to_visit.add(b) for b in graph[new]["related"] if b not in visited]
- subgraphs.append(list(visited))
-
-
- print "SUBGRPAHS"
- pprint(subgraphs)
- print "GRAPH"
- pprint(graph)
- return
-
- # create type dependencies
- typegraph = {}
- for tid, idres in graph.items():
- typegraph[tid] = idres["needs"]
-
- least_needy_type = map(lambda (name, x): (len(x), name), typegraph.items())
- least_needy_type.sort()
-
- types_to_create = create_what(least_needy_type, typegraph)
-
- # create property dependencies
- propgraph = {}
- proptotype = {}
- for tid, idres in graph.items():
- for prop in idres["properties"]:
- propgraph[prop["id"]] = prop["needs"]
- proptotype[prop["id"]] = tid
- least_needy = map(lambda (name, x): (len(x), name), propgraph.items())
- least_needy.sort()
-
- props_to_create = create_what(least_needy, propgraph)
-
- # CREATING STUFF
-
- domainname = "awesome" + str(int(random.random() * 1e10))
- print "\ndomainid", domainname
- print "--------------------------"
- dn = s.create_private_domain(domainname, domainname + "!")
- domain_id = dn.domain_id
-
- better_id = s.mqlread({"id" : domain_id, "a:id" : None})
- domain_id = better_id["a:id"]
-
- for type in types_to_create:
- print type
- key = ""
- if len(graph[type]["key"]) == 1:
- key = graph[type]["key"][0]["value"]
- else:
- expectedname = graph[type]["id"].split("/")[-1]
- if base_id:
- for group in graph[type]["key"]:
- if group["namespace"] == base_id:
- key = group["value"]
- continue
- if key is None:
- key = expectedname
- tip = None
- if graph[type]["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]["value"]
- create_type(s, graph[type]["name"]["value"], key, domain_id,
- included=map(lambda x: convert_name(x["id"], base_id, domain_id), graph[type]["/freebase/type_hints/included_types"]),
- cvt=graph[type]["/freebase/type_hints/mediator"],
- enum=graph[type]["/freebase/type_hints/enumeration"],
- tip=tip)
-
- print "--------------------------"
-
- for prop in props_to_create:
- info = graph[proptotype[prop]]["properties"]
- for i in info:
- if i["id"] == prop:
- schema = convert_name(proptotype[prop], base_id, domain_id)
- print prop
- expected = None
- if i["expected_type"]:
- expected = convert_name(i["expected_type"]["id"], base_id, domain_id)
- for k in i["key"]:
- if k.namespace == proptotype[prop]:
- key = k.value
- if i["/freebase/documented_object/tip"]:
- tip = graph[type]["/freebase/documented_object/tip"]
-
- if i['master_property']:
- reciprocate_property(s, i["name"], key, convert_name(i["master_property"]["id"], base_id, domain_id),
- i["unique"], disambig=i["/freebase/property_hints/disambiguator"], tip=tip)
- elif i['delegated']:
- delegate_property(s, convert_name(i['delegated']['id'], base_id, domain_id), schema,
- expected=expected, tip=tip)
- else:
- create_property(s, i["name"], key, schema, expected, i["unique"],
- disambig=i["/freebase/property_hints/disambiguator"], tip=tip)
-
-
-
-
- print "\ndomain id was", domainname
-"""
-
-
-def convert_name(old_name, operating_base, new_base, only_include=None):
- if old_name in only_include and old_name.startswith(operating_base):
- return new_base + old_name.replace(operating_base, "", 1)
- else:
- return old_name
-
-def create_what(deps, graph):
- create_list = []
- while len(deps) > 0:
- neediness, id = deps.pop(0)
- if neediness == 0:
- create_list.append(id)
- continue
- else:
- work = True
- for req in graph[id]:
- if req not in create_list:
- work = False
- continue
- if work:
- create_list.append(id)
- else:
- deps.append((neediness, id))
- return create_list
-
-
-
-def _get_needed(s, type_id):
- q = TYPE_QUERY
- q.update(id=type_id)
-
- r = s.mqlread(q)
- properties = r.properties
-
- # let's identify who the parent is in order to only include
- # other types in that domain. We don't want to go around including
- # all of commons because someone's a /people/person
- parents = [r["domain"]["id"]]
-
- included_types = map(lambda x: x["id"], r["/freebase/type_hints/included_types"])
- related_types = set(included_types)
- for prop in properties:
- if prop["expected_type"]:
- related_types.add(prop["expected_type"])
-
- # we have two different types of relationships: required and related.
- # related can be used to generate subgraphs of types
- # required is used to generate the dependency graph of types
-
- related = return_relevant(related_types, parents)
- requires = return_relevant(included_types, parents)
-
- # get property information
- properties = r["properties"]
- for prop in properties:
- dependent_on = set()
- if prop["master_property"]:
- dependent_on.add(prop["master_property"])
- if prop["delegated"]:
- dependent_on.add(prop["delegated"])
-
- prop["__requires"] = return_relevant(dependent_on, parents)
-
- # return all the information along with our special __* properties
- info = r
- info.update(__related=related, __requires=requires, __properties=properties)
-
- return info
-
-
-def return_relevant(start_list, parents):
- final = []
- for item in start_list:
- indomain = False
- for parent in parents:
- if item.startswith(parent):
- indomain = True
- continue
- if indomain:
- final.append(item)
- return final
-
-if __name__ == '__main__':
-
- # create domain
- name = str(int(random.random()*1e10))
- domain_id = s.create_private_domain("coolcat" + name, "Coolcat" + name)["domain_id"]
- domain_id = s.mqlread({"id" : domain_id, "a:id" : None})["a:id"]
- print "domain name", domain_id
-
- # dump information
- #graph = dump_type(s, "/user/nitromaster101/coolcat3194242218/bridge_player", follow_types=True)
- graph = dump_type(s, "/people/person", True)
-
- # upload it somewhere else
- upload_type(s, graph, domain_id, debug=True)
-
-
- print "domain name", domain_id
- #create_type_dependencies(s, type_id="/base/contractbridge/bridge_player")
-
-
diff --git a/schema-manipulation/type_creation.py b/schema-manipulation/type_creation.py
deleted file mode 100644
index b940076..0000000
--- a/schema-manipulation/type_creation.py
+++ /dev/null
@@ -1,470 +0,0 @@
-try:
- import simplejson as json
-except ImportError:
- import json
-
-import urllib
-from freebase.api import HTTPMetawebSession, MetawebError
-
-from freebase.api import LITERAL_TYPE_IDS
-s = HTTPMetawebSession('sandbox.freebase.com', username, password)
-s.login()
-
-def key_exists(s, k):
- q = {
- "id" : k,
- "guid" : None
- }
- return not None == s.mqlread(q)
-
-
-# Object helpers
-def create_object(s, name="", path=None, key=None, namespace=None, included_types=[], create="unless_exists", extra=None):
- if type(included_types) is str:
- included_types = [included_types]
-
- if path and (key or namespace):
- raise Exception("You can't specify both the path and a key and namespace.")
-
- if path:
- key, namespace = get_key_namespace(path)
-
- its = set(included_types)
- if included_types:
- q = [{
- "id|=" : included_types,
- "/freebase/type_hints/included_types" : [{"id" : None}]
- }]
- for res in s.mqlread(q):
- its.update(map(lambda x: x["id"], res["/freebase/type_hints/included_types"]))
-
- wq = {
- "id" : None,
- "name" : name,
- "key" : {
- "namespace" : namespace,
- "value" : key,
- },
- "create" : create
- }
-
- if included_types:
- wq.update(type = [{ "id" : it, "connect" : "insert" } for it in its])
-
- if extra:
- wq.update(extra)
-
- return s.mqlwrite(wq)
-
-
-def connect_object(s, id, newpath, extra=None):
-
- key, namespace = get_key_namespace(newpath)
-
- wq = {
- "id" : id,
- "key" : {
- "namespace" : namespace,
- "value" : key,
- "connect" : "insert"
- }
- }
-
- if extra: wq.update(extra)
-
- return s.mqlwrite(wq)
-
-
-def unconnect_object(s, id, extra=None):
-
- key, namespace = get_key_namespace(id)
-
- wq = {
- "id" : id,
- "key" : {
- "namespace" : namespace,
- "value" : key,
- "connect" : "delete"
- }
- }
- if extra: wq.update(extra)
- return s.mqlwrite(wq)
-
-def move_object(s, oldpath, newpath):
- a = connect_object(s, oldpath, newpath)
- b = unconnect_object(s, oldpath)
- return a, b
-
-def type_object(s, id, type_id):
- q = {
- "id" : type_id,
- "/freebase/type_hints/included_types" : [{"id" : None}]
- }
- included_types = map(lambda x: x["id"], s.mqlread(q)["/freebase/type_hints/included_types"])
-
- wq = {
- "id" : id,
- "type" : [{
- "id" : it,
- "connect" : "insert"
- } for it in included_types + [type_id]]
- }
- return s.mqlwrite(wq)
-
-def get_key_namespace(path):
- split = path.split("/")
- return split[-1], "/".join(split[:-1]) or "/"
-
-
-# type moving
-
-
-# property moving
-
-def connect_property(s, id, newid, **extra):
- split = newid.split("/")
- newschema = "/".join(split[:-1])
- newname = split[-1]
-
- info = get_property_info(s, id)
- info["__raw"].update(extra)
- create_property(s, info["name"], newname, newschema, info["expected_type"], info["unique"], info["/freebase/property_hints/disambiguator"],
- info["/freebase/documented_object/tip"], info["__raw"])
-
-def move_property(s, id, newid, **extra):
- connect_property(s, id, newid, **extra)
- disconnect_schema = {"type" : "/type/property", "schema" : {"connect" : "delete", "id" : "/".join(id.split("/")[:-1]) }}
- unconnect_object(s, id, extra = disconnect_schema)
-
-PROPERTY_QUERY = {
- "optional" : True,
- "type" : "/type/property",
- "delegated" : {},
- "enumeration" : {},
- "expected_type" : {},
- "id" : {},
- "key" : [{
- "namespace" : None,
- "value" : None
- }],
- #"link" : [{}],
- "master_property" : {},
- "name" : {"value" : None, "lang" : "/lang/en", "optional":True},
- "schema" : {"id" : None, "name" : None},
- "unique" : {},
- "unit" : {},
- "/freebase/documented_object/tip" : {"value" : None, "limit":1, "optional" : True},
- "/freebase/property_hints/disambiguator" : {},
- "/freebase/property_hints/display_none" : {},
- "/freebase/property_hints/display_orientation" : {},
- "/freebase/property_hints/enumeration" : {},
- "/freebase/property_hints/dont_display_in_weblinks" : {},
- "/freebase/property_hints/inverse_description" : {},
- }
-
-TYPE_QUERY = {
- "type" : "/type/type",
- "domain" : {},
- "key" : [{"namespace" : None, "value" : None}],
- "name" : {"value" : None, "lang" : "/lang/en", "optional":True},
- "/freebase/type_hints/included_types" : [{}],
- "/freebase/type_hints/mediator" : None,
- "/freebase/type_hints/enumeration" : None,
- "/freebase/type_hints/minor" : None,
- "/freebase/documented_object/tip" : {"value" : None, "limit":1, "optional":True},
- "properties" : {"optional" : True}
- }
-TYPE_QUERY.update(properties=[PROPERTY_QUERY])
-
-
-def get_property_info(s, prop_id):
- q = PROPERTY_QUERY
- q.update(id=prop_id)
- res = s.mqlread(q)
- info = {}
-
- info["name"] = res["name"]["value"]
- if res["schema"]:
- info["schema"] = res["schema"]["id"]
- else: info["schema"] = None
-
- if res["key"]:
- info["keys"] = map(lambda x: (x["value"], x["namespace"]), res["key"])
- else: info["key"] = None
-
- if res["/freebase/documented_object/tip"]:
- info["/freebase/documented_object/tip"] = res["/freebase/documented_object/tip"]["value"]
- else: info["/freebase/documented_object/tip"] = None
-
- for i in ["delegated", "enumeration", "expected_type", "id", "master_property", "unique", "unit",
- "/freebase/property_hints/disambiguator", "/freebase/property_hints/display_none",
- "/freebase/property_hints/display_orientation","/freebase/property_hints/enumeration",
- "/freebase/property_hints/dont_display_in_weblinks", "/freebase/property_hints/inverse_description"]:
-
- if res[i]:
- if isinstance(res[i], basestring):
- info[i] = res[i]
- elif res[i].has_key("id"):
- info[i] = res[i]["id"]
- elif res[i].has_key("value"):
- info[i] = res[i]["value"]
- else:
- raise Exception("There is a problem with getting the property value.")
- else: info[i] = None
-
- # delete the properties that are going to be asked for in create_property
- del res["name"]
- del res["schema"]
- del res["key"]
- del res["expected_type"]
- del res["unique"]
- del res["/freebase/property_hints/disambiguator"]
- del res["/freebase/documented_object/tip"]
-
- # delete other useless things...
- del res["id"]
-
- for i in [k for k, v in res.items() if v is None]:
- del res[i]
-
- info["__raw"] = res
- return info
-
-
-# Create Type
-def create_type(s, name, key, ns, cvt=None, tip=None, enum=None, included=[]):
- if key_exists( s, ns + "/" + key ):
- return
-
- q = {
- "create" : "unconditional",
- "type" : "/type/type",
- "/type/type/domain" : { "connect" : "insert", "id" : ns },
- "name" : {"connect" : "insert", "value" : name, "lang" : "/lang/en" },
- "key" : {
- "connect" : "insert",
- "value" : key,
- "namespace" : ns
- }
- }
-
- if included:
- if isinstance(included, basestring):
- included = [included]
- q = {
- "id|=" : included,
- "/freebase/type_hints/included_types" : [{"id" : None}]
- }
- r = s.mqlread(q)
- included_types = set()
- for i in r:
- included_types.append(map(lambda x: x["id"], i["/freebase/type_hints/included_types"]))
-
- q['/freebase/type_hints/included_types'] = \
- [ {"connect":"insert",
- "id":included_id}
- for included_id in included_types]
-
- if enum:
- pass # TODO. What is enumerator?
-
- if cvt:
- q['/freebase/type_hints/mediator'] = { "connect" : "update", "value" : True }
- if tip:
- q['/freebase/documented_object/tip'] = { "connect" : "update", "value" : tip, "lang" : "/lang/en" }
- return s.mqlwrite(q, use_permission_of=ns)
-
-
-# Create Property
-def create_property(s, name, key, schema, expected, unique, disambig=False, tip=None, extra=None):
- if key_exists(s, schema + "/" + key):
- raise Exception("The key \"%s\" already exists!", schema + "/" + key)
- return
- q = {
- "create" : "unconditional",
- "type" : "/type/property",
- "name" : name,
- "key" : {
- "connect" : "insert",
- "value" : key,
- "namespace" : { "id" : schema },
- },
- "schema" : { "connect" : "insert", "id" : schema },
- "expected_type" : { "connect" : "insert", "id" : expected }
- }
- if unique:
- q['unique'] = { "connect" : "update", "value" : unique }
- if tip:
- q['/freebase/documented_object/tip'] = { "connect" : "update", "value" : tip, "lang" : "/lang/en" }
- if disambig:
- q['/freebase/property_hints/disambiguator'] = { "connect" : "update", "value" : True }
- if extra:
- q.update(extra)
- #print json.dumps(q, indent=2)
- return s.mqlwrite(q, use_permission_of=schema)
-
-def delegate_property(s, p, schema, name=None, key=None, expected=None, tip=None):
- q = {
- "id" : p,
- "type" : "/type/property",
- "name" : None,
- "unique" : None,
- "expected_type" : {"id" : None},
- "key" : None,
- "/freebase/documented_object/tip" : None,
- "/freebase/property_hints/disambiguator" : None
- }
- r = s.mqlread(q)
-
- # If the expected_type of the delegator(master) is a primitive, the delegated's
- # expected_type must be the same
- if r["expected_type"]["id"] in LITERAL_TYPE_IDS:
- if expected:
- print "You can't set the expected_type if the expected_type of the delegated(master) is a primitive"
- expected = r["expected_type"]["id"]
- # If the expected_type of the delegator(master) is not a primitive, the delegated's
- # expected_type can be different
- elif expected is None:
- expected = r["expected_type"]["id"]
-
-
- if not tip and r["/freebase/documented_object/tip"]:
- tip = r["/freebase/documented_object/tip"]
-
- if name is None:
- name = r["name"]
- if key is None:
- key = r["key"]
-
- return create_property(s, name, key, schema, expected, r['unique'],
- r["/freebase/property_hints/disambiguator"],
- tip,
- { "/type/property/delegated" : p})
-
-def reciprocate_property(s, name, key, master, unique, disambig=False, tip=None):
- """ We're creating a reciprocate property of the master property. Let's illustrate
- the idea behind the function with an example.
-
- Say we examine the /visual_art/art_period_movement/associated_artworks property.
- An example of an art_period_movement is the Renaissance, and once associated_artworks
- could be the /en/mona_lisa. In this example, /visual_art/art_period_movement/associated_artworks
- will be the master property, and /visual_art/artwork/period_or_movement will be the reciprocal.
-
- In order to determine the characterists of the reciprocal property, we must examine the master.
- associated_artworks property's schema is /visual_art/art_period_movement and its expected
- type is /visual_art/artwork. Notice the similarity to /visual_art/artwork/period_or_movement.
- period_or_movement's schema is /visual_art/artwork -- art_period_movement's expected type.
- period_or_movement's expected type is /visual_art/art_period_movement -- art_period_movement's
- schema!
-
- So, given a master, the reciprocal's schema is the master's expected type and the reciprocal's
- expected type is the master's schema. """
-
-
- q = {
- "id" : master,
- "/type/property/expected_type" : None,
- "/type/property/schema" : None }
- r = s.mqlread(q)
- ect = r["/type/property/expected_type"]
- schema = r["/type/property/schema"]
- return create_property(s, name, key, ect, schema, unique, disambig, tip,
- extra = { "master_property" : master })
-
-
-# ?
-def make_subclass(s, sub, super):
- q = {
- "id" : super,
- "type" : "/type/type",
- "properties" : [{"id" : None}]
- }
- r = s.mqlread( q )
- for p in map(lambda x: x['id'], r['properties'] ):
- delegate_property(s, p, sub)
- w = {
- "id" : sub,
- "/freebase/type_hints/included_types" : { "connect" : "insert", "id" : super }
- }
- s.mqlwrite(w)
-
-def gogo(base="/base/bingbase"):
-
-
-
- create_type(s, "Bridge Player", "bridge_player", base, tip="A bridge player", included=["/people/person", "/common/topic", base+"/topic"])
- create_type(s, "Bridge Tournament", "bridge_tournament", base, tip="A bridge tournament", included=["/event/event", "/common/topic", base+"/topic"])
- create_type(s, "Bridge Tournament Standings", "bridge_tournament_standings", base, cvt=True, tip="Bridge Tournamen Results")
-
- player = base + "/bridge_player"
- tourney = base + "/bridge_tournament"
- standing = base + "/bridge_tournament_standings"
-
- # tournament standings
- # ideas: create a cvt could be a function, disambig always True, same schema, iono, whatever
- create_property(s, "Year", "year", standing, "/type/datetime", True, disambig=True, tip="Year")
- create_property(s, "First Place", "first_place", standing, player, False, disambig=True)
- create_property(s, "Second Place", "second_place", standing, player, False, disambig=True)
- create_property(s, "Tournament", "tournament", standing, tourney, True, disambig=True)
-
-
- # tournament
- reciprocate_property(s, "Standing", "standing", standing + "/tournament", False, disambig=True)
- create_property(s, "Location", "location", tourney, "/location/citytown", False, disambig=True)
-
- # bridge player
- # standings must be reverses!
- reciprocate_property(s, "First Place Finish", "first_place_finish", standing + "/first_place", False, False)
- reciprocate_property(s, "Second Place Finish", "second_place_finish", standing + "/second_place", False, False)
-
- #delegator property test
- delegate_property(mss, "/people/person/date_of_birth", player, "Date of Birth", "db")
-
- # for cvt: expected_type: cvt, reciprocated property is the property on the cvt
-
-
-# another test... not sure it works
-def create_chapter(s):
- create_type( s, "Chapter", "chapter", "/base/testy", True, "A chapter in one of the books" )
- print "created book!"
- create_property( s, "Book", "book", "/base/testy/chapter",
- "/base/testy/book", True, True, "The book of which this chapter is a part" )
- print "created property!"
- reciprocate_property( s, "/base/testy/chapter/book",
- "Chapters", "chapters", "/base/testy/book", False, False, "Chapters in this book" )
-
-def create_edition(s):
- create_type( s, "Edition", "edition", "/base/testy", True, "An edition of the Aubrey-Maturin series" )
- create_property( s, "Examples", "examples", "/base/testy/edition",
- "/book/book_edition", False, False, "Book editions in this series" )
- w = {
- "id" : "/base/testy/edition",
- "/freebase/type_hints/enumeration" : { "value" : True, "connect" : "update" }
- }
- s.mqlwrite( w )
- w = {
- "create" : "unless_exists",
- "type" :"/base/testy/edition",
- "name" : "W. W. Norton Paperback"
- }
- s.mqlwrite( w )
-
-def create_page_ref(s):
- create_type( s, "Page Reference", "page_ref", "/base/testy", True,
- "A reference to a page in a particular edition" )
- t = "/base/testy/page_ref"
- create_property( s, "Page Number", "page", t, "/type/int", True, True )
- create_property( s, "Edition", "edition", t, "/base/testy/edition", True, True )
-
-def create_mention_properties(s, t):
- create_property( s, "Circumstances", "circumstances", t, "/type/text", True, True,
- "Describe the circumstances of the mention" )
- create_property( s, "Quote", "quote", t, "/type/text", True, True,
- "A short quote from the mentioned location" )
- create_property( s, "Chapter", "chapter", t, "/base/testy/chapter", True, True,
- "The chapter in which the mention takes place" )
- create_property( s, "Page", "page", t, "/base/testy/page_ref", False, True,
- "Page number and Edition" )
- create_property( s, "What", "what", t, "/base/testy/topic", True, True,
- "What is being mentioned" )
-
diff --git a/test/runtests.py b/test/runtests.py
index c90afb7..db2303b 100644
--- a/test/runtests.py
+++ b/test/runtests.py
@@ -16,18 +16,23 @@ def main():
created = True
USERNAME, PASSWORD = getlogindetails.main(create_password_file=True)
USERNAME, PASSWORD = getlogindetails.main()
+
# run tests
import test_freebase
import test_schema_manipulation
+ import test_hardcore_schema_manipulation
s1 = unittest.TestLoader().loadTestsFromTestCase(test_freebase.TestFreebase)
s2 = unittest.TestLoader().loadTestsFromTestCase(test_schema_manipulation.TestSchemaManipulation)
+ s3 = unittest.TestLoader().loadTestsFromTestCase(test_hardcore_schema_manipulation.TestHardcoreSchemaManipulation)
# This is very strange. If you try to do [s1, s2], thereby running freebase tests first,
# two tests in the testschemamanipulation file fail! They fail because of caching issues; if
# I check on freebase, the changes are actually there. I have racked my mind for explanations.
- anotherrun = unittest.TestSuite([s1, s2])
+
+ # this is such a hack, and I'm sorry. The tests run 100% correct individually.
+ anotherrun = unittest.TestSuite([s1, s3, s2])
#run = unittest.TestSuite(suites)
@@ -35,6 +40,7 @@ def main():
if created: os.remove(passwordfile)
return anotherrun
+
if __name__ == '__main__':
diff --git a/schema-manipulation/test_hardcore_schema_manipulation.py b/test/test_hardcore_schema_manipulation.py
index 3ef04b1..aaecf28 100644
--- a/schema-manipulation/test_hardcore_schema_manipulation.py
+++ b/test/test_hardcore_schema_manipulation.py
@@ -4,9 +4,10 @@ import freebase
import random
import time
-from freebase.api import HTTPMetawebSession, MetawebError
+import getlogindetails
-from get_type import dump_type, dump_base, upload_type
+from freebase.api import HTTPMetawebSession, MetawebError
+from freebase.schema import dump_type, dump_base, restore
USERNAME = 'username'
PASSWORD = 'password'
@@ -14,6 +15,11 @@ API_HOST = 'sandbox.freebase.com'
s = freebase.api.HTTPMetawebSession(API_HOST)
+if USERNAME == "username" and PASSWORD == "password":
+ USERNAME, PASSWORD = getlogindetails.main()
+
+s.login(USERNAME, PASSWORD)
+
# Sorry, this is just so annoying to type.
f = lambda x: x["id"]
@@ -21,12 +27,12 @@ class TestHardcoreSchemaManipulation(unittest.TestCase):
def test_copy_an_entire_domain(self):
domain_id = _create_domain()
- ex_domain_id = "/film" # example domain id
- ex_domain_type = "actor"
+ ex_domain_id = "/base/contractbridge" # example domain id
+ ex_domain_type = "bridge_player"
ex_domain_type_id = ex_domain_id + "/" + ex_domain_type
graph = dump_base(s, ex_domain_id)
- upload_type(s, graph, domain_id)
+ restore(s, graph, domain_id)
newperson, realperson = s.mqlreadmulti([{"id" : domain_id + "/" + ex_domain_type, "/type/type/properties" : {"return" : "count" }},
{"id" : ex_domain_type_id, "/type/type/properties" : {"return" : "count" }}])
@@ -41,28 +47,29 @@ class TestHardcoreSchemaManipulation(unittest.TestCase):
realtypes = l(realtypes)
newtypes = l(newtypes)
- print realtypes
- print newtypes
+
self.assertEqual(len(realtypes), len(newtypes))
for i in range(len(realtypes)):
- self.assertEqual(realtypes[i].lsplit("/", 1), newtypes[i].lsplit("/", 1))
+ self.assertEqual(realtypes[i].rsplit("/", 1)[-1], newtypes[i].rsplit("/", 1)[-1])
# - check the properties are the same
def get_properties(types):
properties = set()
- for i in s.mqlreadmulti([[{"id" : id, "/type/type/properties" : {"id" : None}}] for id in types]):
- properties.update(map(f, i["/type/type/properties"]))
+ for i in s.mqlreadmulti([{"id" : id, "/type/type/properties" : [{"id" : None}]} for id in types]):
+ properties.update(map(lambda x: x["id"], i["/type/type/properties"]))
return properties
realproperties = sorted(list(get_properties(realtypes)))
newproperties = sorted(list(get_properties(newtypes)))
- self.assertEqual(realproperties, newproperties)
- for i in range(len(realproperties)):
- self.assertEqual(realtypes[i].lsplit("/", 1), newtypes[i].lsplit("/", 1))
-
- # - check the properties and type's attributes are the same
+ def ignore_base(id): return id.rsplit("/", 1)[-1]
+
+ self.assertEqual(len(realproperties), len(newproperties))
+ self.assertEqual([ignore_base(prop_id) for prop_id in realproperties], [ignore_base(prop_id) for prop_id in newproperties])
+
+ # - check the properties and type's attributes are the same
+
@@ -71,14 +78,15 @@ class TestHardcoreSchemaManipulation(unittest.TestCase):
# if follow_types is True, everything is kosher.
domain_id = _create_domain()
graph = dump_type(s, "/film/actor", follow_types=True)
- upload_type(s, graph, domain_id)
+ restore(s, graph, domain_id)
newactor, realactor = s.mqlreadmulti([{"id" : domain_id + "/actor", "/type/type/properties" : {"return" : "count" }},
- {"id" : "/film/actor", "/type/type/properties" : {"return" : "count" }}])
+ {"id" : "/film/actor", "/type/type/properties" : {"return" : "count" }}])
self.assertEqual(newactor["/type/type/properties"], realactor["/type/type/properties"])
# if follow_types is False, if we try to upload a cvt, it should whine
- self.assertRaises(Exception, lambda: dump_type(s, "/film/actor", follow_types=False))
+ from freebase.schema import CVTError
+ self.assertRaises(CVTError, lambda: dump_type(s, "/film/actor", follow_types=False))
diff --git a/test/test_schema_manipulation.py b/test/test_schema_manipulation.py
index 53ce542..f8453e7 100644
--- a/test/test_schema_manipulation.py
+++ b/test/test_schema_manipulation.py
@@ -31,30 +31,20 @@ f = lambda x: x["id"]
class TestSchemaManipulation(unittest.TestCase):
def test_make_and_type_object(self):
- print domain_id
a = s.create_object("A", path=domain_id + "/a")
self.assertEqual(a.create, "created")
b = s.create_object("B", path=domain_id + "/b", included_types=["/people/person"])
- print s.cookiejar._cookies["sandbox-freebase.com"]
q = { "id" : b.id, "type" : [{"id" : None}] }
types = map(f, s.mqlread(q)["type"])
self.assertEqual("/common/topic" in types, True)
self.assertEqual("/people/person" in types, True)
self.assertEqual("/film/actor" in types, False)
- s.touch(), time.sleep(2), s.touch();
- print s.cookiejar._cookies["sandbox-freebase.com"]
+
type_object(s, b.id, "/film/film_genre")
- print s.cookiejar._cookies["sandbox-freebase.com"]
- s.touch(), time.sleep(2), s.touch();
- #s.mqlwrite({"id" : b.id, "/film/film_genre/films_in_this_genre" : {"id" : "/en/the_taking_of_pelham_1_2_3", "connect" : "insert"}})
types = map(f, s.mqlread(q)["type"])
- print s.cookiejar._cookies["sandbox-freebase.com"]
-
- s.touch(), time.sleep(2), s.touch();
- print types
self.assertEqual("/film/film_genre" in types, True)
self.assertEqual("/media_common/media_genre" in types, True)