-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pretty print models #314
base: main
Are you sure you want to change the base?
pretty print models #314
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #314 +/- ##
==========================================
+ Coverage 62.70% 62.80% +0.09%
==========================================
Files 63 63
Lines 8580 8603 +23
Branches 2444 2447 +3
==========================================
+ Hits 5380 5403 +23
Misses 2583 2583
Partials 617 617 โ View full report in Codecov by Sentry. |
some kind of weird windows vs ubuntu nondeterminism here... I like this! As you might expect I'd like to be careful in rolling this out. |
always <3
I think windows just always passes (it's doing the same thing over here #312 (comment) ) I probably need to update some string matching tests, will do that |
OK so i went to go fix the failing tests, and once i realized what they were doing, rather than updating the string representation i just swapped those out for instance equality checks rather than string equality tests which are a more direct and separate out the string representation from the content of the test. we have a problem tho, because this doesn't quite fix the problem, which is that whenever there is an error or python shows you the object for some reason, you get a huge blob of empty params and you can't see the salient things for that model. the SO. this PR is still imo a step in the right direction, and once/if this is merged then I can go and change the sound good??? I also updated the pretty print methods to preserve the name of the class, rather than just printing as a dict, so now we have ClassDefinition({ 'class_uri': 'schema:Person',
'description': 'A person (alive, dead, undead, or fictional).',
'from_schema': 'https://w3id.org/linkml/examples/personinfo',
'is_a': 'NamedThing',
'mixins': ['HasAliases'],
'name': 'Person',
'slot_usage': { 'primary_email': { 'name': 'primary_email',
'pattern': '^\\S+@[\\S+\\.]+\\S+'}},
'slots': [ 'primary_email', 'birth_date', 'age_in_years', 'gender',
'current_address', 'has_employment_history',
'has_familial_relationships', 'has_interpersonal_relationships',
'has_medical_history']}) and once we implement that change to the metamodel generator it should work recursively. |
OK this is ready to review, opened a pull to main repo that matches. the deal witht he complicated print method that isn't just a call to expand/collapse{'classes': {'Address': {'name': 'Address',
'slots': ['street', 'city', 'altitude']},
'AnyObject': {'class_uri': 'linkml:Any',
'description': 'Example of unconstrained class',
'name': 'AnyObject'},
'AnyOfClasses': {'attributes': {'attribute2': {'any_of': [{'range': 'Person'},
{'range': 'Organization'}],
'name': 'attribute2'}},
'name': 'AnyOfClasses'},
'AnyOfEnums': {'attributes': {'attribute3': {'any_of': [{'range': 'DiagnosisType'},
{'range': 'EmploymentEventType'}],
'name': 'attribute3'}},
'name': 'AnyOfEnums'},
'AnyOfMix': {'attributes': {'attribute4': {'any_of': [{'range': 'integer'},
{'range': 'Person'},
{'range': 'EmploymentEventType'}],
'name': 'attribute4'}},
'name': 'AnyOfMix'},
'AnyOfSimpleType': {'attributes': {'attribute1': {'any_of': [{'range': 'string'},
{'range': 'integer'}],
'name': 'attribute1'}},
'name': 'AnyOfSimpleType'},
'BirthEvent': {'is_a': 'Event',
'name': 'BirthEvent',
'slots': ['in location']},
'CodeSystem': {'name': 'CodeSystem', 'slots': ['id', 'name']},
'Company': {'attributes': {'ceo': {'name': 'ceo',
'range': 'Person',
'slot_uri': 'schema:ceo'}},
'is_a': 'Organization',
'name': 'Company'},
'Concept': {'id_prefixes': ['CODE'],
'name': 'Concept',
'slots': ['id', 'name', 'in code system']},
'Dataset': {'attributes': {'activities': {'inlined': True,
'inlined_as_list': True,
'multivalued': True,
'name': 'activities',
'range': 'activity'},
'code systems': {'inlined_as_list': True,
'multivalued': True,
'name': 'code systems',
'range': 'CodeSystem'},
'companies': {'inlined': True,
'inlined_as_list': True,
'multivalued': True,
'name': 'companies',
'range': 'Company'},
'persons': {'inlined': True,
'inlined_as_list': True,
'multivalued': True,
'name': 'persons',
'range': 'Person'}},
'name': 'Dataset',
'rank': 1,
'slots': ['metadata'],
'tree_root': True},
'DiagnosisConcept': {'close_mappings': ['biolink:Disease'],
'is_a': 'Concept',
'name': 'DiagnosisConcept'},
'EmploymentEvent': {'is_a': 'Event',
'name': 'EmploymentEvent',
'rank': 6,
'slot_usage': {'type': {'any_of': [{'range': 'CordialnessEnum'},
{'range': 'EmploymentEventType'}],
'name': 'type',
'required': False}},
'slots': ['employed at', 'type']},
'Event': {'name': 'Event',
'slots': ['started at time',
'ended at time',
'is current',
'metadata']},
'FakeClass': {'attributes': {'test_attribute': {'name': 'test_attribute'}},
'deprecated': 'this is not a real class, we are '
'using it to test deprecation',
'name': 'FakeClass'},
'FamilialRelationship': {'is_a': 'Relationship',
'name': 'FamilialRelationship',
'rank': 5,
'slot_usage': {'cordialness': {'name': 'cordialness'},
'related to': {'name': 'related '
'to',
'range': 'Person',
'required': True},
'type': {'name': 'type',
'range': 'FamilialRelationshipType',
'required': True}},
'slots': ['cordialness']},
'Friend': {'abstract': True, 'name': 'Friend', 'slots': ['name']},
'HasAliases': {'attributes': {'aliases': {'multivalued': True,
'name': 'aliases',
'slot_uri': 'skos:altLabel'}},
'mixin': True,
'name': 'HasAliases'},
'MarriageEvent': {'is_a': 'Event',
'mixins': ['WithLocation'],
'name': 'MarriageEvent',
'slots': ['married to']},
'MedicalEvent': {'is_a': 'Event',
'name': 'MedicalEvent',
'slots': ['in location',
'diagnosis',
'procedure']},
'Organization': {'description': 'An organization.\n'
'\n'
'This description\n'
'includes newlines\n'
'\n'
'## Markdown headers\n'
'\n'
' * and\n'
' * a\n'
' * list',
'id_prefixes': ['ROR'],
'mixins': ['HasAliases'],
'name': 'Organization',
'rank': 3,
'slots': ['id', 'name']},
'Person': {'attributes': {'is_living': {'name': 'is_living',
'range': 'LifeStatusEnum'}},
'description': 'A person, living or dead',
'exact_mappings': ['schema:Person'],
'id_prefixes': ['P'],
'in_subset': ['subset A'],
'mixins': ['HasAliases'],
'name': 'Person',
'rank': 2,
'see_also': ['https://en.wikipedia.org/wiki/Person',
'schema:Person'],
'slot_usage': {'name': {'name': 'name',
'pattern': '^\\S+ \\S+$'},
'species name': {'equals_string': 'human',
'name': 'species name'},
'stomach count': {'equals_number': 1,
'name': 'stomach '
'count'}},
'slots': ['id',
'name',
'has employment history',
'has familial relationships',
'has medical history',
'age in years',
'addresses',
'has birth event',
'species name',
'stomach count']},
'Place': {'mixins': ['HasAliases'],
'name': 'Place',
'slots': ['id', 'name']},
'ProcedureConcept': {'is_a': 'Concept',
'name': 'ProcedureConcept'},
'Relationship': {'name': 'Relationship',
'slot_usage': {'cordialness': {'name': 'cordialness',
'range': 'CordialnessEnum'}},
'slots': ['started at time',
'ended at time',
'related to',
'type',
'cordialness']},
'Sub sub class 2': {'is_a': 'subclass test',
'name': 'Sub sub class 2'},
'WithLocation': {'mixin': True,
'name': 'WithLocation',
'slots': ['in location']},
'class with spaces': {'attributes': {'slot with space 1': {'name': 'slot '
'with '
'space '
'1'}},
'name': 'class with spaces'},
'subclass test': {'attributes': {'slot with space 2': {'name': 'slot '
'with '
'space '
'2',
'range': 'class '
'with '
'spaces'}},
'is_a': 'class with spaces',
'name': 'subclass test'},
'tub sub class 1': {'description': 'Same depth as Sub sub class 1',
'is_a': 'subclass test',
'name': 'tub sub class 1'}},
'default_curi_maps': ['semweb_context'],
'default_prefix': 'ks',
'default_range': 'string',
'description': 'Kitchen Sink Schema\n'
'\n'
'This schema does not do anything useful. It exists to test '
'all features of linkml.\n'
'\n'
'This particular text field exists to demonstrate markdown '
'within a text field:\n'
'\n'
'Lists:\n'
'\n'
' * a\n'
' * b\n'
' * c\n'
'\n'
'And links, e.g to [Person](Person.md)',
'enums': {'CordialnessEnum': {'name': 'CordialnessEnum',
'permissible_values': {'hateful': {'description': 'spiteful',
'text': 'hateful'},
'heartfelt': {'description': 'warm '
'and '
'hearty '
'friendliness',
'text': 'heartfelt'},
'indifferent': {'description': 'not '
'overly '
'friendly '
'nor '
'obnoxiously '
'spiteful',
'text': 'indifferent'}}},
'DiagnosisType': {'name': 'DiagnosisType',
'permissible_values': {'TODO': {'text': 'TODO'}}},
'EmploymentEventType': {'aliases': ['HR code'],
'description': 'codes for different kinds '
'of employment/HR related '
'events',
'name': 'EmploymentEventType',
'permissible_values': {'FIRE': {'annotations': {'biolink:opposite': {'tag': 'biolink:opposite',
'value': 'HIRE'}},
'meaning': 'bizcodes:002',
'text': 'FIRE'},
'HIRE': {'description': 'event '
'for '
'a '
'new '
'employee',
'meaning': 'bizcodes:001',
'text': 'HIRE'},
'PROMOTION': {'description': 'promotion '
'event',
'meaning': 'bizcodes:003',
'text': 'PROMOTION'},
'TRANSFER': {'description': 'transfer '
'internally',
'meaning': 'bizcodes:004',
'text': 'TRANSFER'}}},
'FamilialRelationshipType': {'name': 'FamilialRelationshipType',
'permissible_values': {'CHILD_OF': {'text': 'CHILD_OF'},
'PARENT_OF': {'text': 'PARENT_OF'},
'SIBLING_OF': {'text': 'SIBLING_OF'}}},
'LifeStatusEnum': {'name': 'LifeStatusEnum',
'permissible_values': {'DEAD': {'text': 'DEAD'},
'LIVING': {'text': 'LIVING'},
'UNKNOWN': {'text': 'UNKNOWN'}}},
'other codes': {'name': 'other codes',
'permissible_values': {'a b': {'text': 'a b'}}}},
'id': 'https://w3id.org/linkml/tests/kitchen_sink',
'imports': ['linkml:types', 'core'],
'name': 'kitchen_sink',
'prefixes': {'A': {'prefix_prefix': 'A',
'prefix_reference': 'http://example.org/activities/'},
'BFO': {'prefix_prefix': 'BFO',
'prefix_reference': 'http://purl.obolibrary.org/obo/BFO_'},
'CODE': {'prefix_prefix': 'CODE',
'prefix_reference': 'http://example.org/code/'},
'P': {'prefix_prefix': 'P',
'prefix_reference': 'http://example.org/person/'},
'RO': {'prefix_prefix': 'RO',
'prefix_reference': 'http://purl.obolibrary.org/obo/RO_'},
'ROR': {'prefix_prefix': 'ROR',
'prefix_reference': 'http://example.org/ror/'},
'biolink': {'prefix_prefix': 'biolink',
'prefix_reference': 'https://w3id.org/biolink/'},
'bizcodes': {'prefix_prefix': 'bizcodes',
'prefix_reference': 'https://example.org/bizcodes/'},
'dce': {'prefix_prefix': 'dce',
'prefix_reference': 'http://purl.org/dc/elements/1.1/'},
'ks': {'prefix_prefix': 'ks',
'prefix_reference': 'https://w3id.org/linkml/tests/kitchen_sink/'},
'lego': {'prefix_prefix': 'lego',
'prefix_reference': 'http://geneontology.org/lego/'},
'linkml': {'prefix_prefix': 'linkml',
'prefix_reference': 'https://w3id.org/linkml/'},
'pav': {'prefix_prefix': 'pav',
'prefix_reference': 'http://purl.org/pav/'},
'schema': {'prefix_prefix': 'schema',
'prefix_reference': 'http://schema.org/'},
'skos': {'prefix_prefix': 'skos',
'prefix_reference': 'http://www.w3.org/2004/02/skos/core#'}},
'see_also': ['https://example.org/'],
'slots': {'addresses': {'multivalued': True,
'name': 'addresses',
'range': 'Address'},
'age in years': {'description': 'number of years since birth',
'in_subset': ['subset A', 'subset B'],
'maximum_value': 999,
'minimum_value': 0,
'name': 'age in years',
'range': 'integer'},
'altitude': {'name': 'altitude', 'range': 'decimal'},
'city': {'name': 'city'},
'cordialness': {'name': 'cordialness'},
'diagnosis': {'inlined': True,
'name': 'diagnosis',
'range': 'DiagnosisConcept'},
'employed at': {'in_subset': ['subset A'],
'name': 'employed at',
'range': 'Company'},
'has birth event': {'name': 'has birth event',
'range': 'BirthEvent'},
'has employment history': {'in_subset': ['subset B'],
'inlined_as_list': True,
'multivalued': True,
'name': 'has employment history',
'range': 'EmploymentEvent',
'rank': 7},
'has familial relationships': {'in_subset': ['subset B'],
'inlined_as_list': True,
'multivalued': True,
'name': 'has familial relationships',
'range': 'FamilialRelationship'},
'has marriage history': {'in_subset': ['subset B'],
'inlined_as_list': True,
'multivalued': True,
'name': 'has marriage history',
'range': 'MarriageEvent'},
'has medical history': {'in_subset': ['subset B'],
'inlined_as_list': True,
'multivalued': True,
'name': 'has medical history',
'range': 'MedicalEvent',
'rank': 5},
'in code system': {'name': 'in code system', 'range': 'CodeSystem'},
'in location': {'annotations': {'biolink:opposite': {'tag': 'biolink:opposite',
'value': 'location_of'}},
'name': 'in location',
'range': 'Place'},
'is current': {'name': 'is current', 'range': 'boolean'},
'life_status': {'name': 'life_status', 'range': 'LifeStatusEnum'},
'married to': {'name': 'married to', 'range': 'Person'},
'metadata': {'description': 'Example of a slot that has an '
'unconstrained range',
'name': 'metadata',
'range': 'AnyObject'},
'mixin_slot_I': {'mixin': True, 'name': 'mixin_slot_I'},
'procedure': {'inlined': True,
'name': 'procedure',
'range': 'ProcedureConcept'},
'related to': {'name': 'related to'},
'species name': {'name': 'species name',
'pattern': '^[A-Z]+[a-z]+(-[A-Z]+[a-z]+)?\\\\.[A-Z]+(-[0-9]{4})?$'},
'stomach count': {'name': 'stomach count', 'range': 'integer'},
'street': {'name': 'street'},
'tree_slot_A': {'name': 'tree_slot_A', 'slot_uri': 'ks:A'},
'tree_slot_B': {'is_a': 'tree_slot_A',
'name': 'tree_slot_B',
'slot_uri': 'ks:B'},
'tree_slot_C': {'is_a': 'tree_slot_B',
'mixins': ['mixin_slot_I'],
'name': 'tree_slot_C',
'slot_uri': 'ks:C'},
'type': {'name': 'type'}},
'source_file': 'tests/test_generators/input/kitchen_sink.yaml',
'subsets': {'subset A': {'aliases': ['A'],
'comments': ['this subset is meaningless, it is just '
'here for testing',
'another comment'],
'description': 'test subset A\n'
'\n'
'This is a subset for testing',
'name': 'subset A',
'rank': 2},
'subset B': {'aliases': ['B'],
'description': 'test subset B',
'name': 'subset B',
'rank': 1}},
'title': 'Kitchen Sink Schema'} and this is what this PR does: expand/collapseSchemaDefinition({
'name': 'kitchen_sink',
'description': ('Kitchen Sink Schema\n'
'\n'
'This schema does not do anything useful. It exists to test all features of '
'linkml.\n'
'\n'
'This particular text field exists to demonstrate markdown within a text '
'field:\n'
'\n'
'Lists:\n'
'\n'
' * a\n'
' * b\n'
' * c\n'
'\n'
'And links, e.g to [Person](Person.md)'),
'title': 'Kitchen Sink Schema',
'see_also': ['https://example.org/'],
'id': 'https://w3id.org/linkml/tests/kitchen_sink',
'imports': ['linkml:types', 'core'],
'prefixes': {'pav': Prefix({'prefix_prefix': 'pav', 'prefix_reference': 'http://purl.org/pav/'}),
'dce': Prefix({'prefix_prefix': 'dce', 'prefix_reference': 'http://purl.org/dc/elements/1.1/'}),
'lego': Prefix({'prefix_prefix': 'lego', 'prefix_reference': 'http://geneontology.org/lego/'}),
'linkml': Prefix({'prefix_prefix': 'linkml', 'prefix_reference': 'https://w3id.org/linkml/'}),
'biolink': Prefix({'prefix_prefix': 'biolink', 'prefix_reference': 'https://w3id.org/biolink/'}),
'ks': Prefix({
'prefix_prefix': 'ks',
'prefix_reference': 'https://w3id.org/linkml/tests/kitchen_sink/'
}),
'RO': Prefix({'prefix_prefix': 'RO', 'prefix_reference': 'http://purl.obolibrary.org/obo/RO_'}),
'BFO': Prefix({'prefix_prefix': 'BFO', 'prefix_reference': 'http://purl.obolibrary.org/obo/BFO_'}),
'CODE': Prefix({'prefix_prefix': 'CODE', 'prefix_reference': 'http://example.org/code/'}),
'ROR': Prefix({'prefix_prefix': 'ROR', 'prefix_reference': 'http://example.org/ror/'}),
'A': Prefix({'prefix_prefix': 'A', 'prefix_reference': 'http://example.org/activities/'}),
'P': Prefix({'prefix_prefix': 'P', 'prefix_reference': 'http://example.org/person/'}),
'skos': Prefix({
'prefix_prefix': 'skos',
'prefix_reference': 'http://www.w3.org/2004/02/skos/core#'
}),
'bizcodes': Prefix({'prefix_prefix': 'bizcodes', 'prefix_reference': 'https://example.org/bizcodes/'}),
'schema': Prefix({'prefix_prefix': 'schema', 'prefix_reference': 'http://schema.org/'})},
'default_curi_maps': ['semweb_context'],
'default_prefix': 'ks',
'default_range': 'string',
'subsets': {'subset A': SubsetDefinition({
'name': 'subset A',
'description': 'test subset A\n\nThis is a subset for testing',
'comments': ['this subset is meaningless, it is just here for testing', 'another comment'],
'aliases': ['A'],
'rank': 2
}),
'subset B': SubsetDefinition({'name': 'subset B', 'description': 'test subset B', 'aliases': ['B'], 'rank': 1})},
'enums': {'FamilialRelationshipType': EnumDefinition({
'name': 'FamilialRelationshipType',
'permissible_values': {'SIBLING_OF': PermissibleValue({'text': 'SIBLING_OF'}),
'PARENT_OF': PermissibleValue({'text': 'PARENT_OF'}),
'CHILD_OF': PermissibleValue({'text': 'CHILD_OF'})}
}),
'DiagnosisType': EnumDefinition({
'name': 'DiagnosisType',
'permissible_values': {'TODO': PermissibleValue({'text': 'TODO'})}
}),
'EmploymentEventType': EnumDefinition({
'name': 'EmploymentEventType',
'description': 'codes for different kinds of employment/HR related events',
'aliases': ['HR code'],
'permissible_values': {'HIRE': PermissibleValue({'text': 'HIRE', 'description': 'event for a new employee', 'meaning': 'bizcodes:001'}),
'FIRE': PermissibleValue({
'text': 'FIRE',
'meaning': 'bizcodes:002',
'annotations': {'biolink:opposite': Annotation(tag='biolink:opposite',
value='HIRE',
extensions={},
annotations={})}
}),
'PROMOTION': PermissibleValue({'text': 'PROMOTION', 'description': 'promotion event', 'meaning': 'bizcodes:003'}),
'TRANSFER': PermissibleValue({'text': 'TRANSFER', 'description': 'transfer internally', 'meaning': 'bizcodes:004'})}
}),
'other codes': EnumDefinition({
'name': 'other codes',
'permissible_values': {'a b': PermissibleValue({'text': 'a b'})}
}),
'LifeStatusEnum': EnumDefinition({
'name': 'LifeStatusEnum',
'permissible_values': {'LIVING': PermissibleValue({'text': 'LIVING'}),
'DEAD': PermissibleValue({'text': 'DEAD'}),
'UNKNOWN': PermissibleValue({'text': 'UNKNOWN'})}
}),
'CordialnessEnum': EnumDefinition({
'name': 'CordialnessEnum',
'permissible_values': {'heartfelt': PermissibleValue({'text': 'heartfelt', 'description': 'warm and hearty friendliness'}),
'hateful': PermissibleValue({'text': 'hateful', 'description': 'spiteful'}),
'indifferent': PermissibleValue({
'text': 'indifferent',
'description': 'not overly friendly nor obnoxiously spiteful'
})}
})},
'slots': {'employed at': SlotDefinition({'name': 'employed at', 'in_subset': ['subset A'], 'range': 'Company'}),
'is current': SlotDefinition({'name': 'is current', 'range': 'boolean'}),
'has employment history': SlotDefinition({
'name': 'has employment history',
'in_subset': ['subset B'],
'rank': 7,
'multivalued': True,
'range': 'EmploymentEvent',
'inlined_as_list': True
}),
'has marriage history': SlotDefinition({
'name': 'has marriage history',
'in_subset': ['subset B'],
'multivalued': True,
'range': 'MarriageEvent',
'inlined_as_list': True
}),
'has medical history': SlotDefinition({
'name': 'has medical history',
'in_subset': ['subset B'],
'rank': 5,
'multivalued': True,
'range': 'MedicalEvent',
'inlined_as_list': True
}),
'has familial relationships': SlotDefinition({
'name': 'has familial relationships',
'in_subset': ['subset B'],
'multivalued': True,
'range': 'FamilialRelationship',
'inlined_as_list': True
}),
'married to': SlotDefinition({'name': 'married to', 'range': 'Person'}),
'in location': SlotDefinition({
'name': 'in location',
'annotations': {'biolink:opposite': Annotation(tag='biolink:opposite',
value='location_of',
extensions={},
annotations={})},
'range': 'Place'
}),
'diagnosis': SlotDefinition({'name': 'diagnosis', 'range': 'DiagnosisConcept', 'inlined': True}),
'procedure': SlotDefinition({'name': 'procedure', 'range': 'ProcedureConcept', 'inlined': True}),
'addresses': SlotDefinition({'name': 'addresses', 'multivalued': True, 'range': 'Address'}),
'age in years': SlotDefinition({
'name': 'age in years',
'description': 'number of years since birth',
'in_subset': ['subset A', 'subset B'],
'range': 'integer',
'minimum_value': 0,
'maximum_value': 999
}),
'related to': SlotDefinition({'name': 'related to'}),
'type': SlotDefinition({'name': 'type'}),
'street': SlotDefinition({'name': 'street'}),
'city': SlotDefinition({'name': 'city'}),
'has birth event': SlotDefinition({'name': 'has birth event', 'range': 'BirthEvent'}),
'in code system': SlotDefinition({'name': 'in code system', 'range': 'CodeSystem'}),
'metadata': SlotDefinition({
'name': 'metadata',
'description': 'Example of a slot that has an unconstrained range',
'range': 'AnyObject'
}),
'species name': SlotDefinition({
'name': 'species name',
'pattern': '^[A-Z]+[a-z]+(-[A-Z]+[a-z]+)?\\\\.[A-Z]+(-[0-9]{4})?$'
}),
'stomach count': SlotDefinition({'name': 'stomach count', 'range': 'integer'}),
'tree_slot_A': SlotDefinition({'name': 'tree_slot_A', 'slot_uri': 'ks:A'}),
'tree_slot_B': SlotDefinition({'name': 'tree_slot_B', 'is_a': 'tree_slot_A', 'slot_uri': 'ks:B'}),
'tree_slot_C': SlotDefinition({
'name': 'tree_slot_C',
'is_a': 'tree_slot_B',
'mixins': ['mixin_slot_I'],
'slot_uri': 'ks:C'
}),
'mixin_slot_I': SlotDefinition({'name': 'mixin_slot_I', 'mixin': True}),
'life_status': SlotDefinition({'name': 'life_status', 'range': 'LifeStatusEnum'}),
'cordialness': SlotDefinition({'name': 'cordialness'}),
'altitude': SlotDefinition({'name': 'altitude', 'range': 'decimal'})},
'classes': {'AnyOfSimpleType': ClassDefinition({
'name': 'AnyOfSimpleType',
'attributes': {'attribute1': SlotDefinition({
'name': 'attribute1',
'any_of': [AnonymousSlotExpression({'range': 'string'}),
AnonymousSlotExpression({'range': 'integer'})]
})}
}),
'AnyOfClasses': ClassDefinition({
'name': 'AnyOfClasses',
'attributes': {'attribute2': SlotDefinition({
'name': 'attribute2',
'any_of': [AnonymousSlotExpression({'range': 'Person'}),
AnonymousSlotExpression({'range': 'Organization'})]
})}
}),
'AnyOfEnums': ClassDefinition({
'name': 'AnyOfEnums',
'attributes': {'attribute3': SlotDefinition({
'name': 'attribute3',
'any_of': [AnonymousSlotExpression({'range': 'DiagnosisType'}),
AnonymousSlotExpression({'range': 'EmploymentEventType'})]
})}
}),
'AnyOfMix': ClassDefinition({
'name': 'AnyOfMix',
'attributes': {'attribute4': SlotDefinition({
'name': 'attribute4',
'any_of': [AnonymousSlotExpression({'range': 'integer'}),
AnonymousSlotExpression({'range': 'Person'}),
AnonymousSlotExpression({'range': 'EmploymentEventType'})]
})}
}),
'HasAliases': ClassDefinition({
'name': 'HasAliases',
'mixin': True,
'attributes': {'aliases': SlotDefinition({'name': 'aliases', 'slot_uri': 'skos:altLabel', 'multivalued': True})}
}),
'Friend': ClassDefinition({'name': 'Friend', 'abstract': True, 'slots': ['name']}),
'Person': ClassDefinition({
'name': 'Person',
'id_prefixes': ['P'],
'description': 'A person, living or dead',
'in_subset': ['subset A'],
'see_also': ['https://en.wikipedia.org/wiki/Person', 'schema:Person'],
'exact_mappings': ['schema:Person'],
'rank': 2,
'mixins': ['HasAliases'],
'slots': ['id', 'name', 'has employment history', 'has familial relationships',
'has medical history', 'age in years', 'addresses', 'has birth event',
'species name', 'stomach count'],
'slot_usage': {'name': SlotDefinition({'name': 'name', 'pattern': '^\\S+ \\S+$'}),
'species name': SlotDefinition({'name': 'species name', 'equals_string': 'human'}),
'stomach count': SlotDefinition({'name': 'stomach count', 'equals_number': 1})},
'attributes': {'is_living': SlotDefinition({'name': 'is_living', 'range': 'LifeStatusEnum'})}
}),
'Organization': ClassDefinition({
'name': 'Organization',
'id_prefixes': ['ROR'],
'description': ('An organization.\n'
'\n'
'This description\n'
'includes newlines\n'
'\n'
'## Markdown headers\n'
'\n'
' * and\n'
' * a\n'
' * list'),
'rank': 3,
'mixins': ['HasAliases'],
'slots': ['id', 'name']
}),
'Place': ClassDefinition({'name': 'Place', 'mixins': ['HasAliases'], 'slots': ['id', 'name']}),
'Address': ClassDefinition({'name': 'Address', 'slots': ['street', 'city', 'altitude']}),
'Concept': ClassDefinition({
'name': 'Concept',
'id_prefixes': ['CODE'],
'slots': ['id', 'name', 'in code system']
}),
'DiagnosisConcept': ClassDefinition({'name': 'DiagnosisConcept', 'close_mappings': ['biolink:Disease'], 'is_a': 'Concept'}),
'ProcedureConcept': ClassDefinition({'name': 'ProcedureConcept', 'is_a': 'Concept'}),
'Event': ClassDefinition({
'name': 'Event',
'slots': ['started at time', 'ended at time', 'is current', 'metadata']
}),
'Relationship': ClassDefinition({
'name': 'Relationship',
'slots': ['started at time', 'ended at time', 'related to', 'type', 'cordialness'],
'slot_usage': {'cordialness': SlotDefinition({'name': 'cordialness', 'range': 'CordialnessEnum'})}
}),
'FamilialRelationship': ClassDefinition({
'name': 'FamilialRelationship',
'rank': 5,
'is_a': 'Relationship',
'slots': ['cordialness'],
'slot_usage': {'type': SlotDefinition({'name': 'type', 'range': 'FamilialRelationshipType', 'required': True}),
'related to': SlotDefinition({'name': 'related to', 'range': 'Person', 'required': True}),
'cordialness': SlotDefinition({'name': 'cordialness'})}
}),
'BirthEvent': ClassDefinition({'name': 'BirthEvent', 'is_a': 'Event', 'slots': ['in location']}),
'EmploymentEvent': ClassDefinition({
'name': 'EmploymentEvent',
'rank': 6,
'is_a': 'Event',
'slots': ['employed at', 'type'],
'slot_usage': {'type': SlotDefinition({
'name': 'type',
'required': False,
'any_of': [AnonymousSlotExpression({'range': 'CordialnessEnum'}),
AnonymousSlotExpression({'range': 'EmploymentEventType'})]
})}
}),
'MedicalEvent': ClassDefinition({
'name': 'MedicalEvent',
'is_a': 'Event',
'slots': ['in location', 'diagnosis', 'procedure']
}),
'WithLocation': ClassDefinition({'name': 'WithLocation', 'mixin': True, 'slots': ['in location']}),
'MarriageEvent': ClassDefinition({
'name': 'MarriageEvent',
'is_a': 'Event',
'mixins': ['WithLocation'],
'slots': ['married to']
}),
'Company': ClassDefinition({
'name': 'Company',
'is_a': 'Organization',
'attributes': {'ceo': SlotDefinition({'name': 'ceo', 'slot_uri': 'schema:ceo', 'range': 'Person'})}
}),
'CodeSystem': ClassDefinition({'name': 'CodeSystem', 'slots': ['id', 'name']}),
'Dataset': ClassDefinition({
'name': 'Dataset',
'rank': 1,
'slots': ['metadata'],
'attributes': {'persons': SlotDefinition({
'name': 'persons',
'multivalued': True,
'range': 'Person',
'inlined': True,
'inlined_as_list': True
}),
'companies': SlotDefinition({
'name': 'companies',
'multivalued': True,
'range': 'Company',
'inlined': True,
'inlined_as_list': True
}),
'activities': SlotDefinition({
'name': 'activities',
'multivalued': True,
'range': 'activity',
'inlined': True,
'inlined_as_list': True
}),
'code systems': SlotDefinition({
'name': 'code systems',
'multivalued': True,
'range': 'CodeSystem',
'inlined_as_list': True
})},
'tree_root': True
}),
'FakeClass': ClassDefinition({
'name': 'FakeClass',
'deprecated': 'this is not a real class, we are using it to test deprecation',
'attributes': {'test_attribute': SlotDefinition({'name': 'test_attribute'})}
}),
'class with spaces': ClassDefinition({
'name': 'class with spaces',
'attributes': {'slot with space 1': SlotDefinition({'name': 'slot with space 1'})}
}),
'subclass test': ClassDefinition({
'name': 'subclass test',
'is_a': 'class with spaces',
'attributes': {'slot with space 2': SlotDefinition({'name': 'slot with space 2', 'range': 'class with spaces'})}
}),
'Sub sub class 2': ClassDefinition({'name': 'Sub sub class 2', 'is_a': 'subclass test'}),
'tub sub class 1': ClassDefinition({
'name': 'tub sub class 1',
'description': 'Same depth as Sub sub class 1',
'is_a': 'subclass test'
}),
'AnyObject': ClassDefinition({
'name': 'AnyObject',
'description': 'Example of unconstrained class',
'class_uri': 'linkml:Any'
})},
'source_file': 'tests/test_generators/input/kitchen_sink.yaml'
}) i actually can't emphasize enough how much of a quality of life improvement this is - it might seem like a trivial thing, but it is one of the very first things i noticed when i was using linkml - never print the models, ever, because they will totally wipe out your shell's traceback buffer and offer nothing of value. when working with small schemas with one or two classes this is totally infuriating because you've only set like 5 properties and somehow are getting like 1000 lines of text back when you're trying to see what the hell anything is. this pr makes it actually pretty manageable to work with linkml interactively, i was being delightfully surprised while debugging it. i think it's worth the complexity of the manual string formatting i do here |
i have been using this locally for working with linkml today and i think y'all are gonna love it. really changes how possible it is to read and debug problems in the code :) |
This is really great! Just one Q - the syntax is a bit of a hybrid between python and a kind of OO-json. I agree a plain json serialization is less desirable as the typing becomes implicit. Any thoughts as to making the output pure python that evaluates to the objects that are printed. This could be done with |
Id be fine with either! The instantiation syntax would be tricky bc i am using pformat to handle all the other python objects, so it would be a different kind of hybrid syntax, but adding a |
looks like the upstream tests are confused by the autoversioning... |
Yes yes thats this: #319 |
hi i'm โ๐ธโโ๐นโโ๐ทโโ๐ฎโโ๐ณโโ๐ฌโ โ๐ทโโ๐ชโโ๐ตโโ๐ทโโ๐ชโโ๐ธโโ๐ชโโ๐ณโโ๐นโโ๐ฆโโ๐นโโ๐ฎโโ๐ดโโ๐ณโ โ๐ดโโ๐ซโ โ๐ฒโโ๐ดโโ๐ฉโโ๐ชโโ๐ฑโ โ๐ฉโโ๐ชโโ๐ซโโ๐ฎโโ๐ณโโ๐ฎโโ๐นโโ๐ฎโโ๐ดโโ๐ณโ
you might remember me from other print statements such as
>>> sv = SchemaView('tests/test_loaders_dumpers/input/personinfo.yaml') >>> cls = sv.get_class('Person') >>> print(cls) ClassDefinition(name='Person', id_prefixes=[], id_prefixes_are_closed=None, definition_uri=None, local_names={}, conforms_to=None, implements=[], instantiates=[], extensions={}, annotations={}, description='A person (alive, dead, undead, or fictional).', alt_descriptions={}, title=None, deprecated=None, todos=[], notes=[], comments=[], examples=[], in_subset=[], from_schema='https://w3id.org/linkml/examples/personinfo', imported_from=None, source=None, in_language=None, see_also=[], deprecated_element_has_exact_replacement=None, deprecated_element_has_possible_replacement=None, aliases=[], structured_aliases={}, mappings=[], exact_mappings=[], close_mappings=[], related_mappings=[], narrow_mappings=[], broad_mappings=[], created_by=None, contributors=[], created_on=None, last_updated_on=None, modified_by=None, status=None, rank=None, categories=[], keywords=[], is_a='NamedThing', abstract=None, mixin=None, mixins=['HasAliases'], apply_to=[], values_from=[], string_serialization=None, slots=['primary_email', 'birth_date', 'age_in_years', 'gender', 'current_address', 'has_employment_history', 'has_familial_relationships', 'has_interpersonal_relationships', 'has_medical_history'], slot_usage={'primary_email': SlotDefinition(name='primary_email', id_prefixes=[], id_prefixes_are_closed=None, definition_uri=None, local_names={}, conforms_to=None, implements=[], instantiates=[], extensions={}, annotations={}, description=None, alt_descriptions={}, title=None, deprecated=None, todos=[], notes=[], comments=[], examples=[], in_subset=[], from_schema=None, imported_from=None, source=None, in_language=None, see_also=[], deprecated_element_has_exact_replacement=None, deprecated_element_has_possible_replacement=None, aliases=[], structured_aliases={}, mappings=[], exact_mappings=[], close_mappings=[], related_mappings=[], narrow_mappings=[], broad_mappings=[], created_by=None, contributors=[], created_on=None, last_updated_on=None, modified_by=None, status=None, rank=None, categories=[], keywords=[], is_a=None, abstract=None, mixin=None, mixins=[], apply_to=[], values_from=[], string_serialization=None, singular_name=None, domain=None, slot_uri=None, multivalued=None, array=None, inherited=None, readonly=None, ifabsent=None, list_elements_unique=None, list_elements_ordered=None, shared=None, key=None, identifier=None, designates_type=None, alias=None, owner=None, domain_of=[], subproperty_of=None, symmetric=None, reflexive=None, locally_reflexive=None, irreflexive=None, asymmetric=None, transitive=None, inverse=None, is_class_field=None, transitive_form_of=None, reflexive_transitive_form_of=None, role=None, is_usage_slot=None, usage_slot_name=None, relational_role=None, slot_group=None, is_grouping_slot=None, path_rule=None, disjoint_with=[], children_are_mutually_disjoint=None, union_of=[], range=None, range_expression=None, enum_range=None, required=None, recommended=None, inlined=None, inlined_as_list=None, minimum_value=None, maximum_value=None, pattern='^\\S+@[\\S+\\.]+\\S+', structured_pattern=None, unit=None, implicit_prefix=None, value_presence=None, equals_string=None, equals_string_in=[], equals_number=None, equals_expression=None, exact_cardinality=None, minimum_cardinality=None, maximum_cardinality=None, has_member=None, all_members=None, none_of=[], exactly_one_of=[], any_of=[], all_of=[])}, attributes={}, class_uri='schema:Person', subclass_of=None, union_of=[], defining_slots=[], tree_root=None, unique_keys={}, rules=[], classification_rules=[], slot_names_unique=None, represents_relationship=None, disjoint_with=[], children_are_mutually_disjoint=None, any_of=[], exactly_one_of=[], none_of=[], all_of=[], slot_conditions={})
well today i'm here to talk to you about
edited, updated format: