Merge pull request #356 from Nick-Hall/json-schema

Convert get_schema methods to use JSON Schema
This commit is contained in:
Nick Hall 2017-02-17 22:05:23 +00:00 committed by GitHub
commit 7f07ad2637
35 changed files with 905 additions and 529 deletions

View File

@ -1419,14 +1419,6 @@ class DbReadBase:
"""
raise NotImplementedError
def _hash_name(self, table, name):
"""
Used in SQL functions to eval expressions involving selected
data.
"""
name = self.get_table_func(table, "class_func").get_field_alias(name)
return name.replace(".", "__")
class DbWriteBase(DbReadBase):
"""

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -80,6 +81,38 @@ class Address(SecondaryObject, PrivacyBase, CitationBase, NoteBase, DateBase,
LocationBase.unserialize(self, location)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .date import Date
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"street": {"type": "string"},
"locality": {"type": "string"},
"city": {"type": "string"},
"county": {"type": "string"},
"state": {"type": "string"},
"country": {"type": "string"},
"postal": {"type": "string"},
"phone": {"type": "string"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -220,6 +221,30 @@ class Attribute(AttributeRoot, CitationBase, NoteBase):
self.type.unserialize(the_type)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"type": AttributeType.get_schema(),
"value": {"type": "string"}
}
}
def get_referenced_handles(self):
"""
Return the list of (classname, handle) tuples for all directly

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -36,7 +37,6 @@ from .notebase import NoteBase
from .refbase import RefBase
from .childreftype import ChildRefType
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -90,6 +90,32 @@ class ChildRef(SecondaryObject, PrivacyBase, CitationBase, NoteBase, RefBase):
self.mrel.unserialize(mrel)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"ref": {"type": "string",
"maxLength": 50},
"frel": ChildRefType.get_schema(),
"mrel": ChildRefType.get_schema()
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -43,7 +44,6 @@ from .datebase import DateBase
from .tagbase import TagBase
from .attrbase import SrcAttributeBase
from .citationbase import IndirectCitationBase
from .handle import Handle
LOG = logging.getLogger(".citation")
@ -82,23 +82,41 @@ class Citation(MediaBase, NoteBase, SrcAttributeBase, IndirectCitationBase,
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .srcattribute import SrcAttribute
from .mediaref import MediaRef
from .date import Date
return {
"handle": Handle("Citation", "CITATION-HANDLE"),
"gramps_id": str,
"date": Date,
"page": str,
"confidence": str,
"source_handle": Handle("Source", "SOURCE-HANDLE"),
"note_list": [Handle("Note", "NOTE-HANDLE")],
"media_list": [Handle("Media", "MEDIA-HANDLE")],
"srcattr_list": [SrcAttribute],
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"page": {"type": "string"},
"confidence": {"type": "integer",
"minimum": 0,
"maximum": 4},
"source_handle": {"type": "string",
"maxLength": 50},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"srcattr_list": {"type": "array",
"items": SrcAttribute.get_schema()},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
@classmethod

View File

@ -5,6 +5,7 @@
# Copyright (C) 2009-2013 Douglas S. Blank
# Copyright (C) 2013 Paul Franklin
# Copyright (C) 2013-2014 Vassilii Khachaturov
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -692,6 +693,29 @@ class Date:
raise DateError("Invalid date to unserialize")
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"calendar": {"type": "integer"},
"modifier": {"type": "integer"},
"quality": {"type": "integer"},
"dateval": {"type": "array",
"items": {"type": ["integer", "boolean"]}},
"text": {"type": "string"},
"sortval": {"type": "integer"},
"newyear": {"type": "integer"}
}
}
def copy(self, source):
"""
Copy all the attributes of the given Date instance to the present

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -45,7 +46,6 @@ from .datebase import DateBase
from .placebase import PlaceBase
from .tagbase import TagBase
from .eventtype import EventType
from .handle import Handle
LOG = logging.getLogger(".citation")
@ -121,28 +121,42 @@ class Event(CitationBase, NoteBase, MediaBase, AttributeBase,
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .attribute import Attribute
from .citation import Citation
from .note import Note
from .date import Date
from .tag import Tag
from .media import Media
from .mediaref import MediaRef
return {
"handle": Handle("Event", "EVENT-HANDLE"),
"gramps_id": str,
"type": EventType,
"date": Date,
"description": str,
"place": Handle("Place", "PLACE-HANDLE"),
"citation_list": [Citation],
"note_list": [Note],
"media_list": [Media],
"attribute_list": [Attribute],
"change": int,
"tag_list": [Tag],
"private": bool,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"type": EventType.get_schema(),
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"description": {"type": "string"},
"place": {"type": ["string", "null"],
"maxLength": 50},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"},
}
}
@classmethod

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -38,7 +39,6 @@ from .refbase import RefBase
from .eventroletype import EventRoleType
from .const import IDENTICAL, EQUAL, DIFFERENT
from .citationbase import IndirectCitationBase
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -82,18 +82,26 @@ class EventRef(PrivacyBase, NoteBase, AttributeBase, RefBase,
@classmethod
def get_schema(cls):
"""
Returns the schema for EventRef.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the fields to types.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .attribute import Attribute
return {
"private": bool,
"note_list": [Handle("Note", "NOTE-HANDLE")],
"attribute_list": [Attribute],
"ref": Handle("Event", "EVENT-HANDLE"),
"role": EventRoleType,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"ref": {"type": "string",
"maxLength": 50},
"role": EventRoleType.get_schema(),
}
}
@classmethod

View File

@ -3,7 +3,7 @@
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
# Copyright (C) 2011 Tim G L Lyons
#
# This program is free software; you can redistribute it and/or modify
@ -49,7 +49,6 @@ from .tagbase import TagBase
from .childref import ChildRef
from .familyreltype import FamilyRelType
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
LOG = logging.getLogger(".citation")
@ -129,26 +128,50 @@ class Family(CitationBase, NoteBase, MediaBase, AttributeBase, LdsOrdBase,
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .mediaref import MediaRef
from .ldsord import LdsOrd
from .childref import ChildRef
from .attribute import Attribute
return {
"handle": Handle("Family", "FAMILY-HANDLE"),
"gramps_id": str,
"father_handle": Handle("Person", "PERSON-HANDLE"),
"mother_handle": Handle("Person", "PERSON-HANDLE"),
"child_ref_list": [ChildRef],
"type": FamilyRelType,
"event_ref_list": [EventRef],
"media_list": [MediaRef],
"attribute_list": [Attribute],
"lds_ord_list": [LdsOrd],
"citation_list": [Handle("Citation", "CITATION-HANDLE")],
"note_list": [Handle("Note", "NOTE-HANDLE")],
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"father_handle": {"type": ["string", "null"],
"maxLength": 50},
"mother_handle": {"type": ["string", "null"],
"maxLength": 50},
"child_ref_list": {"type": "array",
"items": ChildRef.get_schema()},
"type": FamilyRelType.get_schema(),
"event_ref_list": {"type": "array",
"items": EventRef.get_schema()},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"lds_ord_list": {"type": "array",
"items": LdsOrd.get_schema()},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
@classmethod

View File

@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -207,6 +208,22 @@ class GrampsType(object, metaclass=GrampsTypeMeta):
"""Convert the object to a serialized tuple of data. """
return (self.__value, self.__string)
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"string": {"type": "string"},
}
}
@classmethod
def get_labels(cls, _):
return {

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -155,6 +156,35 @@ class LdsOrd(SecondaryObject, CitationBase, NoteBase,
DateBase.unserialize(self, date)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .date import Date
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"type": {"type": "integer"},
"place": {"type": "string"},
"famc": {"type": ["null", "string"]},
"temple": {"type": "string"},
"status": {"type": "integer"},
"private": {"type": "boolean"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -71,6 +72,30 @@ class Location(SecondaryObject, LocationBase):
LocationBase.unserialize(self, lbase)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"street": {"type": "string"},
"locality": {"type": "string"},
"city": {"type": "string"},
"county": {"type": "string"},
"state": {"type": "string"},
"country": {"type": "string"},
"postal": {"type": "string"},
"phone": {"type": "string"},
"parish": {"type": "string"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -3,7 +3,7 @@
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
# Copyright (C) 2011 Tim G L Lyons
#
# This program is free software; you can redistribute it and/or modify
@ -45,7 +45,6 @@ from .notebase import NoteBase
from .datebase import DateBase
from .attrbase import AttributeBase
from .tagbase import TagBase
from .handle import Handle
LOG = logging.getLogger(".citation")
@ -121,27 +120,38 @@ class Media(CitationBase, NoteBase, DateBase, AttributeBase,
@classmethod
def get_schema(cls):
"""
Returns the schema for EventRef.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the fields to types.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .attribute import Attribute
from .date import Date
return {
"handle": Handle("Media", "MEDIA-HANDLE"),
"gramps_id": str,
"path": str,
"mime": str,
"desc": str,
"checksum": str,
"attribute_list": [Attribute],
"citation_list": [Handle("Citation", "CITATION-HANDLE")],
"note_list": [Handle("Note", "NOTE-HANDLE")],
"change": int,
"date": Date,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"path": {"type": "string"},
"mime": {"type": "string"},
"desc": {"type": "string"},
"checksum": {"type": "string"},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string"}},
"change": {"type": "integer"},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
@classmethod

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -37,7 +38,6 @@ from .notebase import NoteBase
from .refbase import RefBase
from .attrbase import AttributeBase
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -73,21 +73,33 @@ class MediaRef(SecondaryObject, PrivacyBase, CitationBase, NoteBase, RefBase,
@classmethod
def get_schema(cls):
"""
Returns the schema for MediaRef.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the fields to types.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .attribute import Attribute
from .citation import Citation
from .note import Note
return {
"private": bool,
"citation_list": [Citation],
"note_list": [Note],
"attribute_list": [Attribute],
"ref": Handle("Media", "MEDIA-HANDLE"),
"rect": tuple, # or None if (0,0,0,0)
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"ref": {"type": "string",
"maxLength": 50},
"rect": {"oneOf": [{"type": "null"},
{"type": "array",
"items": {"type": "integer"},
"minItems": 4,
"maxItems": 4}]}
}
}
def unserialize(self, data):

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -37,7 +38,6 @@ from .notebase import NoteBase
from .datebase import DateBase
from .surnamebase import SurnameBase
from .nametype import NameType
from .handle import Handle
from .const import IDENTICAL, EQUAL, DIFFERENT
from .date import Date
from gramps.gen.const import GRAMPS_LOCALE as glocale
@ -152,23 +152,38 @@ class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase,
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .surname import Surname
return {
"private": bool,
"citation_list": [Handle("Citation", "CITATION-HANDLE")],
"note_list": [Handle("Note", "NOTE-HANDLE")],
"date": Date,
"first_name": str,
"surname_list": [Surname],
"suffix": str,
"title": str,
"type": NameType,
"group_as": str,
"sort_as": str,
"display_as": str,
"call": str,
"nick": str,
"famnick": str,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"first_name": {"type": "string"},
"surname_list": {"type": "array",
"items": Surname.get_schema()},
"suffix": {"type": "string"},
"title": {"type": "string"},
"type": NameType.get_schema(),
"group_as": {"type": "string"},
"sort_as": {"type": "integer"},
"display_as": {"type": "integer"},
"call": {"type": "string"},
"nick": {"type": "string"},
"famnick": {"type": "string"}
}
}
def is_empty(self):

View File

@ -3,7 +3,7 @@
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -34,7 +34,6 @@ from .tagbase import TagBase
from .notetype import NoteType
from .styledtext import StyledText
from .styledtexttagtype import StyledTextTagType
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -98,17 +97,27 @@ class Note(BasicPrimaryObject):
@classmethod
def get_schema(cls):
"""
The schema for Note.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"handle": Handle("Note", "NOTE-HANDLE"),
"gramps_id": str,
"text": StyledText,
"format": int,
"type": NoteType,
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"text": StyledText.get_schema(),
"format": {"type": "integer"},
"type": NoteType.get_schema(),
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
@classmethod

View File

@ -3,7 +3,7 @@
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
# Copyright (C) 2011 Tim G L Lyons
#
# This program is free software; you can redistribute it and/or modify
@ -46,7 +46,6 @@ from .attrtype import AttributeType
from .eventroletype import EventRoleType
from .attribute import Attribute
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
@ -187,34 +186,62 @@ class Person(CitationBase, NoteBase, AttributeBase, MediaBase,
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .mediaref import MediaRef
from .address import Address
from .url import Url
from .ldsord import LdsOrd
return {
"handle": Handle("Person", "PERSON-HANDLE"),
"gramps_id": str,
"gender": int,
"primary_name": Name,
"alternate_names": [Name],
"death_ref_index": int,
"birth_ref_index": int,
"event_ref_list": [EventRef],
"family_list": [Handle("Family", "FAMILY-HANDLE")],
"parent_family_list": [Handle("Family", "FAMILY-HANDLE")],
"media_list": [MediaRef],
"address_list": [Address],
"attribute_list": [Attribute],
"urls": [Url],
"lds_ord_list": [LdsOrd],
"citation_list": [Handle("Citation", "CITATION-HANDLE")],
"note_list": [Handle("Note", "NOTE-HANDLE")],
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool,
"person_ref_list": [PersonRef]
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"gender": {"type": "integer",
"minimum": 0,
"maximum": 2},
"primary_name": Name.get_schema(),
"alternate_names": {"type": "array",
"items": Name.get_schema()},
"death_ref_index": {"type": "integer"},
"birth_ref_index": {"type": "integer"},
"event_ref_list": {"type": "array",
"items": EventRef.get_schema()},
"family_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"parent_family_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"address_list": {"type": "array",
"items": Address.get_schema()},
"attribute_list": {"type": "array",
"items": Attribute.get_schema()},
"urls": {"type": "array",
"items": Url.get_schema()},
"lds_ord_list": {"type": "array",
"items": LdsOrd.get_schema()},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"},
"person_ref_list": {"type": "array",
"items": PersonRef.get_schema()}
}
}
def unserialize(self, data):

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -36,7 +37,6 @@ from .citationbase import CitationBase
from .notebase import NoteBase
from .refbase import RefBase
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -83,6 +83,31 @@ class PersonRef(SecondaryObject, PrivacyBase, CitationBase, NoteBase, RefBase):
RefBase.unserialize(self, ref)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"ref": {"type": "string",
"maxLength": 50},
"rel": {"type": "string"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -40,7 +41,6 @@ from .mediabase import MediaBase
from .urlbase import UrlBase
from .tagbase import TagBase
from .location import Location
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -142,28 +142,48 @@ class Place(CitationBase, NoteBase, MediaBase, UrlBase, PrimaryObject):
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .url import Url
from .mediaref import MediaRef
return {
"handle": Handle("Place", "PLACE-HANDLE"),
"gramps_id": str,
"title": str,
"long": str,
"lat": str,
"placeref_list": [PlaceRef],
"name": PlaceName,
"alt_names": [PlaceName],
"place_type": PlaceType,
"code": str,
"alt_loc": [Location],
"urls": [Url],
"media_list": [Handle("Media", "MEDIA-HANDLE")],
"citation_list": [Handle("Citation", "CITATION-HANDLE")],
"note_list": [Handle("Note", "NOTE-HANDLE")],
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"title": {"type": "string"},
"long": {"type": "string"},
"lat": {"type": "string"},
"placeref_list": {"type": "array",
"items": PlaceRef.get_schema()},
"name": PlaceName.get_schema(),
"alt_names": {"type": "array",
"items": PlaceName.get_schema()},
"place_type": PlaceType.get_schema(),
"code": {"type": "string"},
"alt_loc": {"type": "array",
"items": Location.get_schema()},
"urls": {"type": "array",
"items": Url.get_schema()},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"citation_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
def unserialize(self, data):

View File

@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2015 Nick Hall
# Copyright (C) 2015,2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -79,6 +79,25 @@ class PlaceName(SecondaryObject, DateBase):
DateBase.unserialize(self, date)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .date import Date
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"value": {"type": "string"},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]},
"lang": {"type": "string"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2013 Nick Hall
# Copyright (C) 2013,2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -32,7 +32,6 @@ from .secondaryobj import SecondaryObject
from .refbase import RefBase
from .datebase import DateBase
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -72,6 +71,25 @@ class PlaceRef(RefBase, DateBase, SecondaryObject):
DateBase.unserialize(self, date)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .date import Date
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"ref": {"type": "string",
"maxLength": 50},
"date": {"oneOf": [{"type": "null"}, Date.get_schema()]}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -35,7 +36,6 @@ from .addressbase import AddressBase
from .urlbase import UrlBase
from .tagbase import TagBase
from .repotype import RepositoryType
from .handle import Handle
from .citationbase import IndirectCitationBase
#-------------------------------------------------------------------------
@ -87,21 +87,35 @@ class Repository(NoteBase, AddressBase, UrlBase, IndirectCitationBase,
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .address import Address
from .url import Url
return {
"handle": Handle("Repository", "REPOSITORY-HANDLE"),
"gramps_id": str,
"type": RepositoryType,
"name": str,
"note_list": [Handle("Note", "NOTE-HANDLE")],
"address_list": [Address],
"urls": [Url],
"change": int,
"tag_list": [Handle("Tag", "TAG-HANDLE")],
"private": bool
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"type": RepositoryType.get_schema(),
"name": {"type": "string"},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"address_list": {"type": "array",
"items": Address.get_schema()},
"urls": {"type": "array",
"items": Url.get_schema()},
"change": {"type": "integer"},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
def unserialize(self, data):

View File

@ -4,6 +4,7 @@
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -35,7 +36,6 @@ from .notebase import NoteBase
from .refbase import RefBase
from .srcmediatype import SourceMediaType
from .const import IDENTICAL, EQUAL, DIFFERENT
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -81,6 +81,29 @@ class RepoRef(SecondaryObject, PrivacyBase, NoteBase, RefBase):
RefBase.unserialize(self, ref)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"ref": {"type": "string",
"maxLength": 50},
"call_number": {"type": "string"},
"media_type": SourceMediaType.get_schema(),
"private": {"type": "boolean"}
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -5,6 +5,7 @@
# Copyright (C) 2010 Michiel D. Nauta
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -37,7 +38,6 @@ from .tagbase import TagBase
from .attrbase import SrcAttributeBase
from .reporef import RepoRef
from .const import DIFFERENT, EQUAL, IDENTICAL
from .handle import Handle
from .citationbase import IndirectCitationBase
#-------------------------------------------------------------------------
@ -100,25 +100,40 @@ class Source(MediaBase, NoteBase, SrcAttributeBase, IndirectCitationBase,
@classmethod
def get_schema(cls):
"""
Return the schema as a dictionary for this class.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
from .srcattribute import SrcAttribute
from .reporef import RepoRef
from .url import Url
from .mediaref import MediaRef
return {
"handle": Handle("Source", "SOURCE-HANDLE"),
"gramps_id": str,
"title": str,
"author": str,
"pubinfo": str,
"note_list": [Handle("Note", "NOTE-HANDLE")],
"media_list": [Handle("Media", "MEDIA-HANDLE")],
"abbrev": str,
"change": int,
"srcattr_list": [SrcAttribute],
"reporef_list": [RepoRef],
"tag_list": [Handle("Tag", "")],
"private": bool
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"gramps_id": {"type": "string"},
"title": {"type": "string"},
"author": {"type": "string"},
"pubinfo": {"type": "string"},
"note_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"media_list": {"type": "array",
"items": MediaRef.get_schema()},
"abbrev": {"type": "string"},
"change": {"type": "integer"},
"srcattr_list": {"type": "array",
"items": SrcAttribute.get_schema()},
"reporef_list": {"type": "array",
"items": RepoRef.get_schema()},
"tag_list": {"type": "array",
"items": {"type": "string",
"maxLength": 50}},
"private": {"type": "boolean"}
}
}
def unserialize(self, data):

View File

@ -2,6 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -53,3 +54,21 @@ class SrcAttribute(AttributeRoot):
else:
self.type = SrcAttributeType()
self.value = ""
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"type": SrcAttributeType.get_schema(),
"value": {"type": "string"}
}
}

View File

@ -3,6 +3,7 @@
#
# Copyright (C) 2008 Zsolt Foldvari
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -291,11 +292,19 @@ class StyledText:
@classmethod
def get_schema(cls):
"""
The schema for StyledText.
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"string": str,
"tags": [StyledTextTag],
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"string": {"type": "string"},
"tags": {"type": "array",
"items": StyledTextTag.get_schema()}
}
}
@classmethod

View File

@ -3,6 +3,7 @@
#
# Copyright (C) 2008 Zsolt Foldvari
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -84,3 +85,25 @@ class StyledTextTag:
self.name = StyledTextTagType()
self.name.unserialize(the_name)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"name": StyledTextTagType.get_schema(),
"value": {"type": ["null", "string", "integer"]},
"ranges": {"type": "array",
"items": {"type": "array",
"items": {"type": "integer"},
"minItems": 2,
"maxItems": 2}}
}
}

View File

@ -3,6 +3,7 @@
#
# Copyright (C) 2010 Benny Malengier
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -73,12 +74,22 @@ class Surname(SecondaryObject):
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"surname": str,
"prefix": str,
"primary": str,
"origintype": NameOriginType,
"connector": str
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"surname": {"type": "string"},
"prefix": {"type": "string"},
"primary": {"type": "boolean"},
"origintype": NameOriginType.get_schema(),
"connector": {"type": "string"}
}
}
@classmethod

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
@ -155,21 +155,6 @@ class TableObject(BaseObject):
"""
return {}
@classmethod
def field_aliases(cls):
"""
Return dictionary of alias to full field names
for this object class.
"""
return {}
@classmethod
def get_field_alias(cls, alias):
"""
Return full field name for an alias, if one.
"""
return cls.field_aliases().get(alias, alias)
@classmethod
def get_schema(cls):
"""
@ -177,219 +162,21 @@ class TableObject(BaseObject):
"""
return {}
@classmethod
def get_extra_secondary_fields(cls):
"""
Return a list of full field names and types for secondary
fields that are not directly listed in the schema.
"""
return []
@classmethod
def get_index_fields(cls):
"""
Return a list of full field names for indices.
"""
return []
@classmethod
def get_secondary_fields(cls):
"""
Return all seconday fields and their types
Return all secondary fields and their types
"""
from .handle import HandleClass
return ([(key.lower(), value)
for (key, value) in cls.get_schema().items()
if value in [str, int, float, bool] or
isinstance(value, HandleClass)] +
cls.get_extra_secondary_fields())
@classmethod
def get_label(cls, field, _):
"""
Get the associated label given a field name of this object.
No index positions allowed on lists.
"""
chain = field.split(".")
path = cls._follow_schema_path(chain[:-1])
labels = path.get_labels(_)
if chain[-1] in labels:
return labels[chain[-1]]
else:
raise Exception("%s has no such label on %s: '%s'" %
(cls, path, field))
@classmethod
def get_field_type(cls, field):
"""
Get the associated label given a field name of this object.
No index positions allowed on lists.
"""
field = cls.get_field_alias(field)
chain = field.split(".")
ftype = cls._follow_schema_path(chain)
return ftype
@classmethod
def _follow_schema_path(cls, chain):
"""
Follow a list of schema items. Return endpoint.
"""
path = cls
for part in chain:
schema = path.get_schema()
if part.isdigit():
pass # skip over
elif part in schema.keys():
path = schema[part]
else:
raise Exception("No such field. Valid fields are: %s" % list(schema.keys()))
if isinstance(path, (list, tuple)):
path = path[0]
return path
def get_field(self, field, db=None, ignore_errors=False):
"""
Get the value of a field.
"""
field = self.__class__.get_field_alias(field)
chain = field.split(".")
path = self._follow_field_path(chain, db, ignore_errors)
return path
def _follow_field_path(self, chain, db=None, ignore_errors=False):
"""
Follow a list of items. Return endpoint(s) only.
With the db argument, can do joins across tables.
self - current object
returns - None, endpoint, of recursive list of endpoints
"""
from .handle import HandleClass
# start with [self, self, chain, path_to=[]]
# results = []
# expand when you reach multiple answers [obj, chain_left, []]
# if you get to an endpoint, put results
# go until nothing left to expand
todo = [(self, self, [], chain)]
results = []
while todo:
parent, current, path_to, chain = todo.pop()
#print("expand:", parent.__class__.__name__,
# current.__class__.__name__,
# path_to,
# chain)
keep_going = True
p = 0
while p < len(chain) and keep_going:
#print("while:", path_to, chain[p:])
part = chain[p]
if hasattr(current, part): # attribute
current = getattr(current, part)
path_to.append(part)
# need to consider current+part if current is list:
elif isinstance(current, (list, tuple)):
if part.isdigit():
# followed by index, so continue here
if int(part) < len(current):
current = current[int(part)]
path_to.append(part)
elif ignore_errors:
current = None
keeping_going = False
else:
raise Exception("invalid index position")
else: # else branch! in middle, split paths
for i in range(len(current)):
#print("split list:", self.__class__.__name__,
# current.__class__.__name__,
# path_to[:],
# [str(i)] + chain[p:])
todo.append([self, current, path_to[:], [str(i)] + chain[p:]])
current = None
keep_going = False
else: # part not found on this self
# current is a handle
# part is something on joined object
if parent:
ptype = parent.__class__.get_field_type(".".join(path_to))
if isinstance(ptype, HandleClass):
if db:
# start over here:
obj = None
if current:
try:
obj = ptype.join(db, current)
except HandleError:
if ignore_errors:
obj = None
else:
raise
if part == "self":
current = obj
path_to = []
#print("split self:", obj.__class__.__name__,
# current.__class__.__name__,
# path_to,
# chain[p + 1:])
todo.append([obj, current, path_to, chain[p + 1:]])
elif obj:
current = getattr(obj, part)
#print("split :", obj.__class__.__name__,
# current.__class__.__name__,
# [part],
# chain[p + 1:])
todo.append([obj, current, [part], chain[p + 1:]])
current = None
keep_going = False
else:
raise Exception("Can't join without database")
elif part == "self":
pass
elif ignore_errors:
pass
else:
raise Exception("%s is not a valid field of %s; use %s" %
(part, current, dir(current)))
current = None
keep_going = False
p += 1
if keep_going:
results.append(current)
if len(results) == 1:
return results[0]
elif len(results) == 0:
return None
else:
return results
def set_field(self, field, value, db=None, ignore_errors=False):
"""
Set the value of a basic field (str, int, float, or bool).
value can be a string or actual value.
Returns number of items changed.
"""
field = self.__class__.get_field_alias(field)
chain = field.split(".")
path = self._follow_field_path(chain[:-1], db, ignore_errors)
ftype = self.get_field_type(field)
# ftype is str, bool, float, or int
value = (value in ['True', True]) if ftype is bool else value
return self._set_fields(path, chain[-1], value, ftype)
def _set_fields(self, path, attr, value, ftype):
"""
Helper function to handle recursive lists of items.
"""
from .handle import HandleClass
if isinstance(path, (list, tuple)):
count = 0
for item in path:
count += self._set_fields(item, attr, value, ftype)
elif isinstance(ftype, HandleClass):
setattr(path, attr, value)
count = 1
else:
setattr(path, attr, ftype(value))
count = 1
return count
result = []
for (key, value) in cls.get_schema()["properties"].items():
schema_type = value.get("type")
if isinstance(schema_type, list):
schema_type.remove("null")
schema_type = schema_type[0]
elif isinstance(schema_type, dict):
schema_type = None
if schema_type in ("string", "integer", "number", "boolean"):
result.append((key.lower(),
schema_type,
value.get("maxLength")))
return result

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Nick Hall
# Copyright (C) 2010,2017 Nick Hall
# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
@ -29,7 +29,6 @@ Tag object for Gramps.
#
#-------------------------------------------------------------------------
from .tableobj import TableObject
from .handle import Handle
#-------------------------------------------------------------------------
#
@ -104,14 +103,24 @@ class Tag(TableObject):
@classmethod
def get_schema(cls):
"""
Return the schema for Tag
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"handle": Handle("Tag", "TAG-HANDLE"),
"name": str,
"color": str,
"priority": int,
"change": int,
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"handle": {"type": "string",
"maxLength": 50},
"name": {"type": "string"},
"color": {"type": "string",
"maxLength": 13},
"priority": {"type": "integer",
"minimum": 0},
"change": {"type": "integer"}
}
}
@classmethod

View File

@ -1,69 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2016 Gramps Development Team
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" Tests for using database fields """
import unittest
from gramps.gen.db import DbTxn
from gramps.gen.db.utils import make_database
from ..import (Person, Surname, Name, NameType, Family, FamilyRelType,
Event, EventType, Source, Place, PlaceName, Citation, Date,
Repository, RepositoryType, Media, Note, NoteType,
StyledText, StyledTextTag, StyledTextTagType, Tag,
ChildRef, ChildRefType, Attribute, MediaRef, AttributeType,
Url, UrlType, Address, EventRef, EventRoleType, RepoRef,
FamilyRelType, LdsOrd, MediaRef, PersonRef, PlaceType,
SrcAttribute, SrcAttributeType)
class FieldBaseTest(unittest.TestCase):
def setUp(self):
db = make_database("inmemorydb")
db.load(None)
with DbTxn("Test", db) as trans:
# Add some people:
person1 = Person()
person1.primary_name = Name()
person1.primary_name.surname_list.append(Surname())
person1.primary_name.surname_list[0].surname = "Smith"
person1.gramps_id = "I0001"
db.add_person(person1, trans) # person gets a handle
# Add some families:
family1 = Family()
family1.father_handle = person1.handle
family1.gramps_id = "F0001"
db.add_family(family1, trans)
self.db = db
def test_field_access01(self):
person = self.db.get_person_from_gramps_id("I0001")
self.assertEqual(person.get_field("primary_name.surname_list.0.surname"),
"Smith")
def test_field_join01(self):
family = self.db.get_family_from_gramps_id("F0001")
self.assertEqual(family.get_field("father_handle.primary_name.surname_list.0.surname", self.db),
"Smith")
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,128 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" Unittest for JSON schema """
import os
import unittest
import json
import jsonschema
from .. import (Person, Family, Event, Place, Repository, Source, Citation,
Media, Note, Tag)
from ..serialize import to_json
from ...db.utils import import_as_dict
from ...const import DATA_DIR
from gramps.cli.user import User
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
class BaseTest(unittest.TestCase):
def _schema_test(self, obj):
instance = json.loads(to_json(obj))
try:
jsonschema.validate(instance, self.schema)
except jsonschema.exceptions.ValidationError:
self.fail("JSON Schema validation error")
class PersonTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Person.get_schema()
class FamilyTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Family.get_schema()
class EventTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Event.get_schema()
class PlaceTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Place.get_schema()
class RepositoryTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Repository.get_schema()
class SourceTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Source.get_schema()
class CitationTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Citation.get_schema()
class MediaTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Media.get_schema()
class NoteTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Note.get_schema()
class TagTest(BaseTest):
@classmethod
def setUpClass(cls):
cls.schema = Tag.get_schema()
def generate_case(obj, test_class):
"""
Dynamically generate tests.
"""
def test(self):
self._schema_test(obj)
name = "test_schema_%s_%s" % (obj.__class__.__name__, obj.handle)
setattr(test_class, name, test)
db = import_as_dict(EXAMPLE, User())
for obj in db.iter_people():
generate_case(obj, PersonTest)
for obj in db.iter_families():
generate_case(obj, FamilyTest)
for obj in db.iter_events():
generate_case(obj, EventTest)
for obj in db.iter_places():
generate_case(obj, PlaceTest)
for obj in db.iter_repositories():
generate_case(obj, RepositoryTest)
for obj in db.iter_sources():
generate_case(obj, SourceTest)
for obj in db.iter_citations():
generate_case(obj, CitationTest)
for obj in db.iter_media():
generate_case(obj, MediaTest)
for obj in db.iter_notes():
generate_case(obj, NoteTest)
for obj in db.iter_tags():
generate_case(obj, TagTest)
if __name__ == "__main__":
unittest.main()

View File

@ -3,6 +3,7 @@
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009-2013 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -72,6 +73,25 @@ class Url(SecondaryObject, PrivacyBase):
self.type.unserialize(type_value)
return self
@classmethod
def get_schema(cls):
"""
Returns the JSON Schema for this class.
:returns: Returns a dict containing the schema.
:rtype: dict
"""
return {
"type": "object",
"properties": {
"_class": {"enum": [cls.__name__]},
"private": {"type": "boolean"},
"path": {"type": "string"},
"desc": {"type": "string"},
"type": UrlType.get_schema()
}
}
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.

View File

@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2015-2016 Douglas S. Blank <doug.blank@gmail.com>
# Copyright (C) 2016 Nick Hall
# Copyright (C) 2016-2017 Nick Hall
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -891,19 +891,19 @@ class DBAPI(DbGeneric):
surname_list.append(row[0])
return surname_list
def _sql_type(self, python_type):
def _sql_type(self, schema_type, max_length):
"""
Given a schema type, return the SQL type for
a new column.
"""
from gramps.gen.lib.handle import HandleClass
if isinstance(python_type, HandleClass):
return "VARCHAR(50)"
elif python_type == str:
return "TEXT"
elif python_type in [bool, int]:
if schema_type == 'string':
if max_length:
return "VARCHAR(%s)" % max_length
else:
return "TEXT"
elif schema_type in ['boolean', 'integer']:
return "INTEGER"
elif python_type in [float]:
elif schema_type == 'number':
return "REAL"
else:
return "BLOB"
@ -918,11 +918,9 @@ class DBAPI(DbGeneric):
"get_secondary_fields"):
continue
table_name = table.lower()
for field_pair in self.get_table_func(
for field, schema_type, max_length in self.get_table_func(
table, "class_func").get_secondary_fields():
field, python_type = field_pair
field = self._hash_name(table, field)
sql_type = self._sql_type(python_type)
sql_type = self._sql_type(schema_type, max_length)
try:
# test to see if it exists:
self.dbapi.execute("SELECT %s FROM %s LIMIT 1"
@ -944,14 +942,12 @@ class DBAPI(DbGeneric):
"""
table = obj.__class__.__name__
fields = self.get_table_func(table, "class_func").get_secondary_fields()
fields = [field for (field, direction) in fields]
fields = [field for (field, schema_type, max_length) in fields]
sets = []
values = []
for field in fields:
value = obj.get_field(field, self, ignore_errors=True)
field = self._hash_name(obj.__class__.__name__, field)
sets.append("%s = ?" % field)
values.append(value)
values.append(getattr(obj, field))
# Derived fields
if table == 'Person':

View File

@ -177,6 +177,7 @@ gramps/gen/lib/tag.py
gramps/gen/lib/test/date_test.py
gramps/gen/lib/test/grampstype_test.py
gramps/gen/lib/test/merge_test.py
gramps/gen/lib/test/schema_test.py
gramps/gen/lib/url.py
gramps/gen/lib/urlbase.py
#