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

ObjectType and Plugins #1787

Merged
merged 67 commits into from
Jan 24, 2022
Merged

ObjectType and Plugins #1787

merged 67 commits into from
Jan 24, 2022

Conversation

devinrsmith
Copy link
Member

Fixes #1766

@devinrsmith
Copy link
Member Author

To try out locally, modify dockerfile docker/server/src/main/docker/Dockerfile and then prepareCompose:

# To test out the deephaven-plugin-matplotlib, uncomment the following:
#RUN set -eux; \
#    python3 -m pip install -q --no-cache-dir \
#    importlib-metadata \
#    https://github.com/deephaven/deephaven-plugin-matplotlib/releases/download/v0.0.1.dev1/deephaven_plugin_matplotlib-0.0.1.dev1-py3-none-any.whl

Start server, run script:

import matplotlib.pyplot as plt

x = [0, 2, 4, 6]
y = [1, 3, 4, 8]
plt.plot(x, y)
plt.xlabel('x values')
plt.ylabel('y values')
plt.title('plotted x and y values')
plt.legend(['line 1'])

m_figure = plt.gcf()

Client tests:

./gradlew java-client-session-examples:installDist
./java-client/session-examples/build/install/java-client-session-examples/bin/fetch-object --variable m_figure > /tmp/m_figure.png
./java-client/session-examples/build/install/java-client-session-examples/bin/subscribe-fields


private final PyDictWrapper dict;

public PythonSnapshot(PyDictWrapper dict) {
Copy link
Member

Choose a reason for hiding this comment

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

aren't these snapshot types just wrappers around the getVariables/getVariable calls? why does each lang need to reimplement the diff?

Copy link
Member Author

Choose a reason for hiding this comment

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

The old version was very inefficient (getVariables is very inefficient for python). In general, I think our ScriptSession interface as a top-level programmatic object leaves a lot to be desired, esp wrt python. Pushing some of the compute changes logic down into python allows us to avoid crossing the JNI boundary as much. I'd like to take it further at some point, as I think more logic can/should be moved into python.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, I'll let this be deferred, but while I also dislike the current AbstractScriptSession/QueryScope abstraction/relationship, I dont think we're tearing out enough in this patch, or designing (i.e. with review) the new approach/api being put here.

If it is a good idea to remove, I'd rather do it in a complete way.

settings.gradle Outdated Show resolved Hide resolved
import dagger.Module;

@Module(includes = {ObjectTypesModule.class})
public interface PluginModule {
Copy link
Member

Choose a reason for hiding this comment

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

does this serve a purpose on its own? it seems like it just pulls in the plugin.ObjectTypesModule?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've got a follow up PR for an application plugin; instead of refactoring the structure in the application plugin, I'm providing the follow-up structure for it here.

return Optional.empty();
}

public synchronized void register(ObjectType type) {
Copy link
Member

Choose a reason for hiding this comment

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

is there no public API to programmatically register a new ObjectType? This class is package-protected, and ObjectTypeLookup doesnt declare this method

Copy link
Member Author

Choose a reason for hiding this comment

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

Right now, I'm thinking that it's only via plugin mechanisms. We could expose the register, but I think it has some non-obvious implications for the script session (and application fields) changeListener wrt "displayble" types.

Copy link
Member

Choose a reason for hiding this comment

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

I'm definitely imagining a use case where a java/groovy user would want to iterate without knocking over the server with every change - just keep calling register (and a matching unregister?) as you tweak the class definition in the console, fetch from the client to work on it. Probably matters less locally, but maybe more on a server deployment.

This might just be in my head - but with such a flexible mechanism (and already threadsafe etc), it seems like a shame to keep it from power users.

Copy link
Member Author

Choose a reason for hiding this comment

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

punting for now #1809

docker/server/src/main/docker/Dockerfile Outdated Show resolved Hide resolved
Comment on lines 37 to 54
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ObjectTypeClassBase<?> that = (ObjectTypeClassBase<?>) o;
if (!name.equals(that.name))
return false;
return clazz.equals(that.clazz);
}

@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + clazz.hashCode();
return result;
}
Copy link
Member

Choose a reason for hiding this comment

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

These seem unnecessary to define.

Copy link
Member

Choose a reason for hiding this comment

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

If ObjectTypeClassBase instances can handle subtypes (as they seem to be able to do, except in the actual registry impl), this could be necessary... something to this effect anyway, traverse the already assembled instances to figure out which one applies to a given object (imagine registering, for example, Object, Number, and Double, make sure String gets the Object instance, Long gets the Number instance, etc)

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't mean for it to handle subtypes ATM. We can update the impl in the future if necessary. I think Ryan is correct, will remove equals/hashcode atm.

@niloc132
Copy link
Member

niloc132 commented Jan 4, 2022

Sorry I ran out of time to write a summary, and wanted to get these earlier thoughts to you. My main worry is that there is too much implementation and not enough API - there are roughly two APIs here, a gRPC/pb one for clients, and a java/python api to declare/instantiate/register the handlers. I mostly would like some improvement at this point on the gRPC/pb side, as I think that is the part we've thought out the most from a consumption perspective the most (and the case where we most want to avoid more than one way to do something).

My main points to stick to:

  • console and application should use the same (in terms of 'shape', not actually the same stream, probably) "This is a named thing with a type", "get this thing, assuming it is this type", "tell me when any bindings change" services.
  • Ditto table attributes, so we can fetch complex objects (including tables) in a consistent way across these 2.5 cases.
  • dh-written client apis should be able to (but not required to) recognize and deserialize the data, but must handle turning internal objects into a real thing. Figures are the main discussed example of this - the js api for example will decode the figure and plug in the various tables, but other APIs might not actually care about the figure contents, and just want to turn internal tickets into tables.

Let's try to chat a bit tomorrow, I'll generate the gwt bindings so that the client refactor can get an update and we can give it a shakedown on figures, expose matlibplot to js?

@devinrsmith devinrsmith requested a review from niloc132 January 6, 2022 22:30
@Singleton
public final class ObjectTypes implements ObjectTypeLookup, ObjectTypeRegistration {

private static final Set<String> RESERVED_TYPE_NAMES_LOWERCASE = Set.of("table", "tablemap", "treetable", "");
Copy link
Member

Choose a reason for hiding this comment

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

should we reserve figure in some way? not sure of the mechanics of how this works, if it makes any more sense to reserve tablemap than figure...

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm more inclined to want to namespace Figure as something like io.deephaven.Figure (doesn't have to be the full Figure class, but something that could be stable and survive implementation refactorings). As it is now, if somebody else tries to install a "Figure" object type, we'll blow up at startup.

Copy link
Member

Choose a reason for hiding this comment

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

Should verify that "tablemap" is going to be a thing (with that word) - but while i agree that our "table" should win over other tables, i'm not sure why our tablemap or treetable would be any more essential than our figures when it comes to serialization to a client.

Copy link
Member Author

Choose a reason for hiding this comment

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

Assuming we can revisit this later.

server/build.gradle Outdated Show resolved Hide resolved
@devinrsmith devinrsmith merged commit 9853bda into deephaven:main Jan 24, 2022
@devinrsmith devinrsmith deleted the fetch-object branch January 24, 2022 21:15
@github-actions github-actions bot locked and limited conversation to collaborators Jan 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Types plugin and FetchObject RPC
4 participants