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

Update documentation to match the new App and Model classes #165

Closed
haydnv opened this issue May 26, 2022 · 6 comments
Closed

Update documentation to match the new App and Model classes #165

haydnv opened this issue May 26, 2022 · 6 comments
Assignees

Comments

@haydnv
Copy link
Owner

haydnv commented May 26, 2022

These pages:

Have been badly out-of-date since Cluster was replaced by App. We should update them based on the App and Model examples in the tests/apps directory.

@smurf-cm
Copy link
Contributor

smurf-cm commented Jun 27, 2022

Hey @haydnv , I may need access to your gitbooks.for the time being if you could review the docs i'll add them to the comments.

@smurf-cm
Copy link
Contributor

Chain: persistent mutable state.

In order to serve a dynamic application, you’ll have to have a way of updating your service’s persistent state. To do this you can use a Chain, a data structure which keeps track of mutations to a Collection in order to maintain the consistency of that State across every replica of an
app.

class Persistent(tc.app.App):
    __uri__ = tc.URI("http://127.0.0.1:8702/test/chain")

    def _configure(self):
        self.rev = tc.Chain.Sync(0)
        tc.app.App.__init__(self)

    # this method looks up the value of "rev" within a transaction
    @tc.get
    def version(self) -> tc.Number:
        return self.rev

    # this method updates the value of "rev" within a transaction
    @tc.post
    def bump(self, txn):
        # note: the value of "version()" must be assigned a name
        # in order to be addressable by the instance method __add__ below
        txn.rev = self.version()
        return self.rev.set(txn.rev + 1)

When you start a TinyChain host with an App definition, it will assume that there is a hosted app with the given URI (”http://…/app/test/chain” in the example above) and attempt to join that App as a replica.
If the app URI has no host address, or is the same as the address of the running host, the host will serve a single replica of a new app.

Watch out for versioning issues! In production, it’s best to end your app URI with a version number which you can update in order to release a new, non-backwards-compatible version with different data and methods. We are attempting to find a solution to this and will be released at a future time.

@smurf-cm
Copy link
Contributor

Object orentation

One of TinyChain’s most powerful features is its object-oriented API.
You can use this to define your own classes, which must inherit from exactly one class, which ultimately inherits from a native class.

For example:

import tinychain as tc

URI = tc.URI("http://example.com/app/area") # <-- edit this

# Specifying `metaclass=tc.Meta` provides JSON encoding functionality for user-defined classes.
# It's only required when subclassing a native class -- subclasses of `Distance` automatically inherit its metaclass.


class Distance(tc.Number, metaclass=tc.Meta):
    __uri__ = URI.append("Distance")

    @tc.get
    def to_feet(self) -> Feet:
        return tc.error.NotImplemented("abstract")

    @tc.get
    def to_meters(self) -> Meters:
        return tc.error.NotImplemented("abstract")


class Feet(Distance):
    __uri__ = URI.append("Feet")

    @tc.get
    def to_feet(self) -> Feet:
        return self

    @tc.get
    def to_meters(self) -> Meters:
        return self / 3.28


class Meters(Distance):
    __uri__ = URI.append("Meters")

    @tc.get
    def to_feet(self) -> Feet:
        return self * 3.28

    @tc.get
    def to_meters(self) -> Meters:
        return self

TinyChain does not have any concept of member visibility, like a “public” or “private” method.
This is because TinyChain objects are meant to be sent over the network and used by client code, making a “private” method is meaningless (and deceptive to the developer implementing it).
If you want to hide an implementation detail from the public API of your class, consider using a helper function outside your class definition.

@smurf-cm
Copy link
Contributor

smurf-cm commented Jun 27, 2022

host your service

Now that we've defined some classes in and a Chain in ...(link to chain docs), it's time to put our service online! You can do this using the same object-oriented API that you used to build the service. For security reasons, TinyChain requires that you load your Cluster configuration from a local file on the host machine; see the next section, for instructions.

from __future__ import annotations
import tinychain as tc 

URI = tc.URI("http://127.0.0.1:8702/demo")


class User(tc.app.Model):
    __uri__ = URI.append("user")

    username = tc.Column("username", tc.String, 100)

    def __init__(self, username):
        self.username = username


class UserService(tc.graph.Graph):
    __uri__ = URI

    @tc.post
    def create_user(self, new_user: User) -> tc.Number:
        user_id = self.user.max_id() + 1
        return tc.After(self.user.insert([user_id], [new_user.username]), user_id)


def start_host(name, apps):
    # I intend to manually kbuild this out and not use the tests code. Once I publish.
    from tests.tctest.process import start_local_host, start_docker

    # return start_local_host(name, apps)
    return start_docker(name, apps)


if __name__ == "__main__":
    # start a new TinyChain host.
    host = start_host("demo", [UserService(models=[User])])

    # verify that it works as expected
    user_id = host.post("/demo/create_user", {"username": "user"})
    print(user_id)
    assert user_id > 0

You can see more in-depth examples in the tests directory.


With this one I think there is potentially a bug in tinychain?, every time I run the code using the latest tinychain bin (0.9.0-beta) i get the following:

start host process on port 8702
bin/tinychain: error while loading shared libraries: libaf.so.3: cannot open shared object file: No such file or directory
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/cormac/workspace/python/tinychain/script.py", line 25, in <module>
    start_host("demo", [Demo()])
  File "/home/cormac/workspace/python/tinychain/script.py", line 19, in start_host
    return start_local_host(name, apps)
  File "/home/cormac/workspace/python/tinychain/tests/tctest/process.py", line 206, in start_local_host
    process.start(wait_time)
  File "/home/cormac/workspace/python/tinychain/tests/tctest/process.py", line 141, in start
    raise RuntimeError(f"TinyChain process crashed on startup")
RuntimeError: TinyChain process crashed on startup

Note that running it with the docker host is fine and works as expected.
Also currently won't work because of issue: #175

@haydnv haydnv assigned haydnv and unassigned smurf-cm Jul 29, 2022
@haydnv
Copy link
Owner Author

haydnv commented Jul 29, 2022

readthedocs.io also has not updated since v0.4

@haydnv
Copy link
Owner Author

haydnv commented Oct 4, 2022

The readthedocs.io issue is now fixed: https://tinychain.readthedocs.io/en/latest/

@haydnv haydnv closed this as completed Jan 16, 2023
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

No branches or pull requests

3 participants