related icon indicating copy to clipboard operation
related copied to clipboard

Feedback Requested

Open imaurer opened this issue 7 years ago • 15 comments

If you are using this library, please post a note here and let me know if you have any luck or any questions....

imaurer avatar Jun 11 '17 14:06 imaurer

Hey! I really like the library - it's really elegant and it works! I've been using it extensively in a package (not-yet publicly available). I'll open a separate issue about the fixed Attrs version (need to support a newer version)

Avsecz avatar Jan 29 '18 17:01 Avsecz

First reasonable library I came across on this 'modern' language. Thanks for doing this. Documentation is a bit lacking and an example with JSON would be nice

GabrielDav avatar Feb 10 '18 23:02 GabrielDav

Looks like a great library, but, I've hit unserializable decimals and enums. Hope, I'll write some fields in a pair of hours.

ambivalentno avatar May 22 '18 17:05 ambivalentno

Thanks @ambivalentno!

Just as an FYI, you can use Enums as ChildFields. But making it an explicit might be helpful.

Nothing with decimals explicitly or implicitly. So great to have them added.

There are a couple of tests with enums: https://github.com/genomoncology/related/search?q=Enum

Specifically: https://github.com/genomoncology/related/search?q=DayType

imaurer avatar May 22 '18 17:05 imaurer

@imaurer Thank you for your clarification about enums. Created https://github.com/genomoncology/related/pull/13 for decimals.

ambivalentno avatar May 22 '18 19:05 ambivalentno

Also, have you thought about serialization/deserialization speed comparison with existing libraries?

ambivalentno avatar May 22 '18 21:05 ambivalentno

Merged the PR. Thanks again. Will update the version shortly.

Which respect to speed comparisons? Do you mean with using ujson instead or json for converting to JSON or comparing related to something like cattrs or schematics?

I'm interested, but not exactly a top priority since I mostly use this library for configuration files and other non-performance critical features. But moar speed is always great.

imaurer avatar May 22 '18 21:05 imaurer

Do you mean with using ujson instead or json for converting to JSON or comparing related to something like cattrs or schematics? smth like cattrs/marshmallow/serpy/etc. Thank you for clarification.

ambivalentno avatar May 23 '18 09:05 ambivalentno

Hello! I'm playing with related and it looks really nice!

Could you help with this case:

conf:
  A:
    type: a
    field_a: 1
  B:
    type: b
    filed_b: 2

At the end, I want to have a list with two different classes:

[
    ClassA(name='A', type='a', field_a=1),
    ClassB(name='B', type='b', field_b=2)
]

is it possible?

olfway avatar Jun 29 '18 20:06 olfway

Hard to tell from an artificial example your exact goals, but both of these examples work. I prefer the 2nd example but it doesn't meet your specific requirement of 2 different child class types. It also uses two special flags in the YAML serializer function.

Example 1

import related


@related.mutable()
class BaseChild(object):
    type = related.StringField()


@related.mutable()
class ChildA(BaseChild):
    field_a = related.IntegerField()


@related.mutable()
class ChildB(BaseChild):
    field_b = related.IntegerField()


@related.mutable()
class Parent(object):
    A = related.ChildField(ChildA)
    B = related.ChildField(ChildB)


@related.mutable()
class Root(object):
    conf = related.ChildField(Parent)


example = """
conf:
  A:
    type: a
    field_a: 1
  B:
    type: b
    field_b: 2
""".strip()

roundtrip = related.to_yaml(related.from_yaml(example, Root)).strip()
print(roundtrip)
assert roundtrip == example

Example 2

@related.mutable()
class ChildAB(object):
    name = related.StringField()
    type = related.StringField()
    field_a = related.IntegerField(required=False)
    field_b = related.IntegerField(required=False)


@related.mutable()
class RootAB(object):
    conf = related.MappingField(ChildAB, "name")


example = """
conf:
  A:
    type: a
    field_a: 1
  B:
    type: b
    field_b: 2
""".strip()

root_ab = related.from_yaml(example, RootAB)
roundtrip = related.to_yaml(
    root_ab, suppress_map_key_values=True, suppress_empty_values=True
).strip()
print(roundtrip)
assert roundtrip == example

Hope that helps! Ian

imaurer avatar Jun 29 '18 22:06 imaurer

Thanks for your answer, Ian!

I want different classes because I want to validate that:

  • ChildA always has "field_a" and no "field_b"
  • ChildB always has "field_b" and no "field_a"

The first example validates it as I want, but unfortunately, I cannot tell how many entries will be in the conf map.

It's a config file and there can be several entries, some with type=a and others with type=b Actually, It's a list of actions, like

actions:
  run-prog-a:
    type: program
    command: /some/program
  run-prog-b
    type: program
    command: /some/other/program
  make-http-call:
    type: http
    url: http://some.site/

So, I want to make sure, that run-prog-* actions will always have "command" field and make-http-* actions will have "url" field instead

olfway avatar Jun 29 '18 22:06 olfway

@olfway since this is so specialized you might want to create your own field type with it's own converter that invokes to_model passing in a class based on a child dictionary value. It's not super hard to do once you understand the pattern.

Here is the "field type" to copy: https://github.com/genomoncology/related/blob/781a33cfa41bba1fc28ac464120fc9bca79e311d/src/related/fields.py#L141

Here is the converter to copy: https://github.com/genomoncology/related/blob/781a33cfa41bba1fc28ac464120fc9bca79e311d/src/related/converters.py#L80

I provided the links to the Mapping Field, but since order probably is important, you might want to consider switching to the Sequence Field as your starting point.

imaurer avatar Jun 29 '18 23:06 imaurer

Thanks, I'll try it

olfway avatar Jun 29 '18 23:06 olfway

I like this library a lot, but I can't get past a problem I'm having with SeqeunceFields.

I have an Authorization object:

@related.mutable
class Authorization():
    id = related.StringField(required=False)
    description = related.StringField(required=False)
    capabilities = related.SequenceField(Capability, required=False)

    @staticmethod
    def load(dictionary):
        return to_model(Authorization, dictionary)

    def provide(self):
        d = to_dict(self)
        return d

But whenever I try to pass a dict with a lift of Capability objects into the load function it gives me an error.

for val in result:
    capability_vals = (val[2], val[3])
    capability_zip = dict(zip(capability_keys, capability_vals))
    capability = Capability.load(capability_zip)
    capability_list.append(capability)

    auth_vals = (val[0], val[1], capability_list)
    auth_zip = dict(zip(auth_keys, auth_vals))
    auth = Authorization.load(auth_zip)

This gives me: WARNING routes : isinstance() arg 2 must be a type or tuple of types

I've tried converting passing in tuple(capabilities_list), a list, a tuple of numbers, a tuple of strings, etc. The only thing that seems to work is passing in capabilities directly as an empty tuple: auth = Authorization.load({"id": "1", "description": "1", "capabilities": ()})

What am I doing wrong?


Edit: I figured it out, I was importing the Authorization class wrong.

bergerr avatar Feb 08 '19 19:02 bergerr

A lot about this library is really appealing, thank you. I've tried it out by starting a DYN implementation with it.

Some of the questions I had while doing it:

  1. Are my reform_as and equal_as functions redundant or foolish?
  2. Should I not be using inheritance so much?
  3. Why does related.to_yaml put single quotes around some enum values but not others?
  4. Am I using (im)mutable decorators rationally?
  5. Can I somehow pass just a sequence/collection of related objects to the constructor of one which has a MappingField of those? It seems redundant to construct a dictionary, when the MappingField itself has the info needed to construct that (child_key).
  6. Any unaddressed glaring abuses of the library?

EDIT: I realize that Q3 is probably because of (broad-)yaml's implicit boolean conversions. Is it possible to disable those, so that yes and no are interpreted as strings and written without quotes?

AndydeCleyre avatar Apr 28 '19 19:04 AndydeCleyre