Skip to content
This repository has been archived by the owner on Mar 16, 2024. It is now read-only.

Commit

Permalink
Backport fix and features from PyEcore
Browse files Browse the repository at this point in the history
  • Loading branch information
aranega committed Jun 23, 2018
1 parent 6cb650c commit c26d4af
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 29 deletions.
16 changes: 8 additions & 8 deletions pyecore/resources/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ def get_resource(self, uri, options=None):
def can_resolve(self, uri_path, from_resource=None):
uri_path = Resource.normalize(uri_path)
fragment = uri_path.rsplit('#', 1)
if len(fragment) == 2:
nb_fragments = len(fragment)
if nb_fragments == 2:
uri_str, fragment = fragment
else:
return False
if uri_str in self.resources:
return True
start = from_resource.uri.normalize() if from_resource else '.'
Expand Down Expand Up @@ -181,12 +180,13 @@ def normalize(self):
return self._uri_norm.get(self.protocol, lambda x: x)(self.plain)
return path.abspath(self.plain)

def relative_from_me(self, uri):
def relative_from_me(self, other_uri):
normalized = path.dirname(self.normalize())
other = uri
if isinstance(uri, URI):
other = uri.normalize()
return path.relpath(other, normalized)
if isinstance(other_uri, URI):
other_normalized = other_uri.normalize()
if other_uri.protocol:
return other_normalized
return path.relpath(other_normalized, normalized)

def apply_relative_from_me(self, relative_path):
parent_path = path.dirname(self.normalize())
Expand Down
57 changes: 37 additions & 20 deletions pyecore/resources/xmi.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,12 @@ def grouper(iterable):
args = [iter(iterable)] * 2
return zip(*args)

schema_tag_list = xmlroot.attrib.get(self.schema_tag)
if schema_tag_list:
self.schema_locations = {prefix: Ecore.EProxy(path, self)
for prefix, path in
grouper(schema_tag_list.split())}
else:
self.schema_locations = {}
self.schema_locations = {}
schema_tag_list = xmlroot.attrib.get(self.schema_tag, '')
for prefix, path in grouper(schema_tag_list.split()):
if '#' not in path:
path = path + '#'
self.schema_locations[prefix] = Ecore.EProxy(path, self)

for root in real_roots:
modelroot = self._init_modelroot(root)
Expand Down Expand Up @@ -146,22 +145,26 @@ def _init_modelroot(self, xmlroot):
return modelroot

@staticmethod
def _decode_eattribute_value(eobject, eattribute, value):
if eattribute.many:
def _decode_eattribute_value(eobject, eattribute, value, from_tag=False):
if eattribute.many and not from_tag:
values = value.split()
results = [eattribute.eType.from_string(x) for x in values]
from_string = eattribute.eType.from_string
results = [from_string(x) for x in values]
eobject.__getattribute__(eattribute.name).extend(results)
elif eattribute.many:
value = eattribute.eType.from_string(value)
eobject.__getattribute__(eattribute.name).append(value)
else:
val = eattribute.eType.from_string(value)
eobject.__setattr__(eattribute.name, val)

def _decode_eobject(self, current_node, parent_eobj):
eobject_info = self._decode_node(parent_eobj, current_node)
feat_container, eobject, eatts, erefs = eobject_info
feat_container, eobject, eatts, erefs, from_tag = eobject_info

# deal with eattributes and ereferences
for eattribute, value in eatts:
self._decode_eattribute_value(eobject, eattribute, value)
self._decode_eattribute_value(eobject, eattribute, value, from_tag)

if erefs:
self._later.append((eobject, erefs))
Expand All @@ -184,7 +187,7 @@ def _is_none_node(self, node):

def _decode_node(self, parent_eobj, node):
if node.tag == 'eGenericType': # Special case, TODO
return (None, None, [], [])
return (None, None, [], [], False)
_, node_tag = self.extract_namespace(node.tag)
feature_container = self._find_in_metacache(parent_eobj, node_tag)
if not feature_container:
Expand All @@ -194,11 +197,11 @@ def _decode_node(self, parent_eobj, node):
node.sourceline,))
if self._is_none_node(node):
parent_eobj.__setattr__(feature_container.name, None)
return (None, None, [], [])
return (None, None, [], [], False)
if node.get('href'):
ref = node.get('href')
proxy = Ecore.EProxy(path=ref, resource=self)
return (feature_container, proxy, [], [])
return (feature_container, proxy, [], [], False)
if self._type_attribute(node):
prefix, _type = self._type_attribute(node).split(':')
if not prefix:
Expand Down Expand Up @@ -227,16 +230,17 @@ def _decode_node(self, parent_eobj, node):
# if hasattr(container, 'python_class'):
# container = container.python_class
# container.__doc__ = annotation_value
return (None, None, tuple(), tuple())
return (None, None, tuple(), tuple(), False)
elif node.text and node.text.strip():
key = node.tag
value = node.text
feature = self._decode_attribute(parent_eobj, key, value)
return (None, parent_eobj, ((feature, value),), tuple())
return (None, parent_eobj, ((feature, value),), tuple(), True)
else:
# idref = node.get('{{{}}}idref'.format(XMI_URL))
# if idref:
# return (None, parent_eobj, [], [(feature_container, idref)])
# return (None, parent_eobj, [],
# [(feature_container, idref)], True)
eobject = etype()

# we sort the node feature (no containments)
Expand All @@ -253,7 +257,7 @@ def _decode_node(self, parent_eobj, node):
else:
erefs.append((feature, value))
self._resolve_mem[eobject.eURIFragment()] = eobject
return (feature_container, eobject, eatts, erefs)
return (feature_container, eobject, eatts, erefs, False)

def _decode_attribute(self, owner, key, value):
namespace, att_name = self.extract_namespace(key)
Expand Down Expand Up @@ -423,7 +427,20 @@ def _go_across(self, obj, serialize_default=False):
elif isinstance(feat, Ecore.EAttribute):
etype = feat.eType
if feat.many and value:
node.attrib[feat_name] = ' '.join(etype.to_string(value))
to_str = etype.to_string
has_special_char = False
result_list = []
for v in value:
string = to_str(v)
if any(x.isspace() for x in string):
has_special_char = True
result_list.append(string)
if has_special_char:
for v in result_list:
sub = etree.SubElement(node, feat_name)
sub.text = v
else:
node.attrib[feat_name] = ' '.join(result_list)
continue
default_value = feat.get_default_value()
if value != default_value or serialize_default:
Expand Down
17 changes: 16 additions & 1 deletion tests/test_resources.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pytest
import pyecore.ecore as Ecore
from pyecore.ecore import *
from pyecore.resources import *
from pyecore.resources import ResourceSet, URI, Resource, global_registry
from pyecore.resources.resource import Global_URI_decoder
from pyecore.resources.resource import HttpURI
from pyecore.resources.xmi import XMIResource
Expand Down Expand Up @@ -345,3 +345,18 @@ def test_resource_normalize_unknown_protocol():

u = URI('platform:/test')
assert u.normalize() == u.plain


def test_resource_normalize_change_protocol():
r = Resource(path.join('..', 'test'))
r.uri = 'pathmap://test'

assert r.uri.normalize() == r.uri.plain
assert r.uri.plain == 'pathmap://test'


def test_resource_normalize_with_protocol():
u1 = URI('test/toto.xmi')
u2 = URI('pathmap://UML_METAMODELS/UML.metamodel.uml')

assert u1.relative_from_me(u2) == u2.plain
8 changes: 8 additions & 0 deletions tests/xmi/test_xmi_deserialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,11 @@ def test_load_xsi_schemaLocation_error():
b_file = path.join('tests', 'xmi', 'xmi-tests', 'b7.xmi')
with pytest.raises(Exception):
rset.get_resource(b_file)


def test_load_xsi_schemaLocation_no_fragment():
rset = ResourceSet()
schema_file = path.join('tests', 'xmi', 'xmi-tests', 'test_schema.xmi')
resource = rset.get_resource(schema_file)

assert len(resource.contents) == 1
36 changes: 36 additions & 0 deletions tests/xmi/test_xmi_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def test_resource_createSaveModifyRead(tmpdir, lib):
class A(object):
name = Ecore.EAttribute('name', Ecore.EString)
age = Ecore.EAttribute('age', Ecore.EInt)
names = Ecore.EAttribute(eType=Ecore.EString, upper=-1)


def test_xmi_ecore_save_load(tmpdir):
Expand Down Expand Up @@ -283,3 +284,38 @@ def test_xmi_save_load_EDate(tmpdir):
rset.metamodel_registry[pack.nsURI] = pack
resource = rset.get_resource(URI(str(f)))
assert resource.contents[0].date == date


def test_xmi_many_string_serialization(tmpdir):
rset = ResourceSet()
rset.metamodel_registry[eClass.nsURI] = eClass

f = tmpdir.mkdir('pyecore-tmp').join('many_string_no_whitespace.xmi')
a1 = A()
a1.names.append('test1')
a1.names.append('test2')
a1.names.append('test3')
resource = rset.create_resource(str(f))
resource.append(a1)
resource.save()
rset.resources.clear()
assert rset.resources == {}
root = rset.get_resource(str(f)).contents[0]
assert 'test1' == root.names[0]
assert 'test2' == root.names[1]
assert 'test3' == root.names[2]

f = tmpdir.join('pyecore-tmp', 'many_string_whitespace.xmi')
a1 = A()
a1.names.append('test 1')
a1.names.append('test 2')
a1.names.append('test3"')
resource = rset.create_resource(str(f))
resource.append(a1)
resource.save()
rset.resources.clear()
assert rset.resources == {}
root = rset.get_resource(str(f)).contents[0]
assert 'test 1' == root.names[0]
assert 'test 2' == root.names[1]
assert 'test3"' == root.names[2]
5 changes: 5 additions & 0 deletions tests/xmi/xmi-tests/test_schema.ecore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="test" nsURI="http://test/1.0" nsPrefix="test">
<eClassifiers xsi:type="ecore:EClass" name="A"/>
</ecore:EPackage>
3 changes: 3 additions & 0 deletions tests/xmi/xmi-tests/test_schema.xmi
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<test:A xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:test="http://test/1.0" xsi:schemaLocation="http://test/1.0 test_schema.ecore"/>

0 comments on commit c26d4af

Please sign in to comment.