Skip to content
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

[DATASOURCE]: Persistent data handler update #478

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

amadolid
Copy link
Collaborator

@amadolid amadolid commented Jun 22, 2024

CHANGES:

!!! IMPORTANT !!!

  • As much as possible, Anchor classes should only communicate with Anchor classes too
  • Architype classes will act as view of Anchor on jaclang perspective
  • JacFeature implementations should be the bridge between Architype and Anchors

!!! --------- !!!

  • ObjectAnchor is now the description of the architype in datasource perspective.
  • datasource uses python's shelve.Shelf if specified. Backed up by memory.
  • Anchors now have synced and unsynced state.
  • Synced Anchors are either retrieve from the datasource or newly created from jaclang
  • Unsynced Anchors are either from reference id or from lazy loaded anchors from existing Synced Anchors
  • Saving Anchors will unsync non self reference to avoid recurssion
  • Access validation now support blacklist and whitelist approach
  • Access can be associated with read or write permission and also with root or node

!!! TO FOLLOW !!!

  • common operation to manipulate access

!!! --------- !!!

@amadolid amadolid mentioned this pull request Jun 22, 2024
jaclang/cli/cli.py Outdated Show resolved Hide resolved
jaclang/cli/cli.py Show resolved Hide resolved
jaclang/cli/cli.py Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/plugin/tests/test_jaseci.py Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
@amadolid amadolid requested a review from ypkang June 27, 2024 14:38
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/cli/cli.py Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
@amadolid amadolid requested a review from ypkang June 27, 2024 18:11
@amadolid amadolid force-pushed the enhancements/persistent-v2 branch 5 times, most recently from ab10a4e to a70412a Compare July 3, 2024 20:02
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/architype.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
jaclang/core/memory.py Outdated Show resolved Hide resolved
@amadolid amadolid requested a review from ypkang July 8, 2024 07:14
@amadolid amadolid force-pushed the enhancements/persistent-v2 branch 2 times, most recently from bad20f1 to 30232ce Compare July 12, 2024 12:30
ypkang
ypkang previously approved these changes Jul 12, 2024
Copy link
Contributor

@ypkang ypkang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am okay with merging this. @marsninja if you sign off, we can 🚢 this.

@amadolid amadolid force-pushed the enhancements/persistent-v2 branch 4 times, most recently from f611dbc to 0e8e210 Compare July 15, 2024 15:37
id_uuid = UUID(int=0)
else:
id_uuid = UUID(id)
super_root = jctx.super_root
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we can call this system_root

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can rename it, tho my initial idea is super_root can be attached to a user. If we rename it to system_root, the implication is it's a non user type root

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah we should change this to system_root

jaclang/cli/cli.py Outdated Show resolved Hide resolved
jaclang/core/context.py Outdated Show resolved Hide resolved
Comment on lines 90 to 93
{
"session": session,
"root": NodeAnchor.ref(root),
"entry": NodeAnchor.ref(node),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure we should be using a free form dictionary here, should perhaps be a type ExecCtxOptions or something

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the initial code here has fixed parameters before. However, as I integrate it, the fields there are too dynamic.
If I set it on Jac specs, will I able to override it on plugin ?

on jaclang args are session, root, entry
jaclang-jaseci request, root, entry (different classes)

Comment on lines +133 to +138
def __eq__(self, other: object) -> bool:
"""Support string comparator."""
if isinstance(other, str):
return self.name == other
return super().__eq__(other)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we need this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there somethign fishy here 😜

Copy link
Collaborator Author

@amadolid amadolid Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ow actually, this is just a workaround since I don't know how the parser works before

but the issue is, disconnect uses string EdgeDir while edge_ref uses the Enum EdgeDir

I realign both on Jac Implementation side to use the Enum
and adding this changes allow it to still support the parser on disconnect using string edgedir

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discuss with @marsninja

def new_init(
self: Architype,
*args: object,
__jac__: Optional[Anchor] = None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this used?

Copy link
Collaborator Author

@amadolid amadolid Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you already have the jac, let say anchor is from the db, it will reuse it instead of creation a new one

jaclang/cli/cli.py Outdated Show resolved Hide resolved
jaclang/cli/cli.py Outdated Show resolved Hide resolved
jaclang/cli/cli.py Outdated Show resolved Hide resolved
Comment on lines +133 to +138
def __eq__(self, other: object) -> bool:
"""Support string comparator."""
if isinstance(other, str):
return self.name == other
return super().__eq__(other)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there somethign fishy here 😜

@amadolid amadolid force-pushed the enhancements/persistent-v2 branch 5 times, most recently from 45b082f to b9cc829 Compare July 23, 2024 00:08
@amadolid amadolid force-pushed the enhancements/persistent-v2 branch 7 times, most recently from 6d4c897 to 6b2ced7 Compare July 30, 2024 02:12
@amadolid
Copy link
Collaborator Author

amadolid commented Aug 6, 2024

Auto Await reference
#514

if self.whitelist:
return self.whitelist, self.anchors.get(anchor, -1)
else:
return self.whitelist, self.anchors.get(anchor, 2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Enum for the access level instead of integer? It will be much more readable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will check it

jaclang/runtimelib/architype.py Show resolved Hide resolved

def populate_dataclasses(cls: type, attributes: dict[str, Any]) -> dict[str, Any]:
"""Populate nested dataclasses."""
from dacite import from_dict
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does introduce a new core dependency dacite for jaclang so i wonder if @marsninja is okay with it.

@amadolid do we have to use this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, although we can create our own. This is to support edge case where attributes are nested dataclasses

# ): Access(**value)
# for key, value in types.items()
# },
# nodes=Access(**data.get("nodes", {})),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the code for the types-based permission for now? it will probably take more than just uncomment these to get it to work when we do want to introduce this later. So for now, I'd like to keep the code cleaner.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will remove it


@staticmethod
def ref(ref_id: str) -> Optional[Anchor]:
"""Return ObjectAnchor instance if ."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finish this docstring.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will update 😅

and self.state.connected == other.state.connected
)
elif isinstance(other, Architype):
return self == other.__jac__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the same comment @marsninja had before -- why do we need to create custom eq for anchor? When do we need to compare anchor with architype?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in context, anchor act as description of a architype. Comparing with anchor is like checking if it only has the same description as it can resync anytime with the latest values (if its on "unloaded" state)

return f"{self.type.value}:{self.name}:{self.id}"

@staticmethod
def ref(ref_id: str) -> Optional[Anchor]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it looks like this ref is overriden for each specific anchor type. So do we still need this one here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anchor.ref is like a non restricted way of referencing. NodeAnchor.ref will only allow node reference id
(same mechanism with Edge and Walker)

This is to support "blind" referencing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is an example scenario where this is usedful?


def sync(self, node: Optional["NodeAnchor"] = None) -> Optional[NodeArchitype]:
"""Retrieve the Architype from db and return."""
return cast(Optional[NodeArchitype], super().sync(node))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to cast to the parent class? instead of just using the inherited function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't revisit it again.
But initially, this is only for forcing the type hinting base on their current class

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah take a look. We might not need this i feel like.

"""Retrieve the Architype from db and return."""
return cast(Optional[NodeArchitype], super().sync(node))

def connect_node(self, nd: NodeAnchor, edg: EdgeAnchor) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edg --> edge?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it looks like we are using nd in some places and node in others. We should unify them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, will update it



class Architype:
"""Architype Protocol."""

_jac_entry_funcs_: list[DSFunc]
_jac_exit_funcs_: list[DSFunc]
__jac_classes__: dict[str, type[Architype]]
__jac_hintings__: dict[str, type]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm what are these for? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jac_classes is similar to subclasses but converted to dict and cached
applicable only on NodeArchitype, EdgeArchitype and WalkerArchitype

jac_hintings is a cached typing.get_type_hints used for walker api generations

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what purpose do they server?

self.jac_machine = JacMachine(base_path)
self.datasource: ShelfStorage = ShelfStorage(session)
self.reports: list[Any] = []
self.super_root = self.load(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we change this to system_root? @marsninja left this comment before. I like system_root better too :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change it to system root tho my concern is, will that imply that its a non user type root?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its okay. It will be like a user is assuming the role of the system and this is their root. I think that still works.

id_uuid = UUID(int=0)
else:
id_uuid = UUID(id)
super_root = jctx.super_root
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah we should change this to system_root

"root": NodeAnchor.ref(root),
"entry": NodeAnchor.ref(node),
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carrying over this comment from the last review -- there was concern of using free form dictionary here. we should discuss

@@ -0,0 +1,31 @@
node A {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is great. But, can we add some more test cases to increase coverage?

  • Update nodes
  • Create connection for nodes (test the connect permission)
  • some common sharing permission scenarios. Are sharing part of jaclang? Or its going to be in jaseci only?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its partially supported.
its supposed to be with plugin function but we can add unit test with manual trigger for now



class Architype:
"""Architype Protocol."""

_jac_entry_funcs_: list[DSFunc]
_jac_exit_funcs_: list[DSFunc]
__jac_classes__: dict[str, type[Architype]]
__jac_hintings__: dict[str, type]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what purpose do they server?

self.jac_machine = JacMachine(base_path)
self.datasource: ShelfStorage = ShelfStorage(session)
self.reports: list[Any] = []
self.super_root = self.load(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its okay. It will be like a user is assuming the role of the system and this is their root. I think that still works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants