Giter Site home page Giter Site logo

pyblish / pyblish-qml Goto Github PK

View Code? Open in Web Editor NEW
114.0 18.0 44.0 2.58 MB

Pyblish QML frontend for Maya 2013+, Houdini 11+, Nuke 8+ and more

License: GNU Lesser General Public License v3.0

Python 55.60% QML 38.23% JavaScript 5.14% Shell 0.04% Dockerfile 0.19% PowerShell 0.80%
pyblish python qml pyqt5

pyblish-qml's Introduction

Pyblish QML

The Pyblish QML project provides a graphical frontend to Pyblish.

Build Status




Requirements

Pyblish QML works with..

  • Standalone
  • Maya 2013+
  • Nuke 8+
  • Houdini 11+
  • Blender 2.79-2.80+

..and requires an external Python (2 or 3) install with PyQt 5.6+ available.

Before use, point to your Python executable like this.

$ set PYBLISH_QML_PYTHON_EXECUTABLE=c:\python27\python.exe

This assumes the Python distribution has access to PyQt5 via e.g. python -c "import PyQt5". If not, you may point to the directory containing it like this.

$ set PYBLISH_QML_PYQT5=c:\path\to\pyqt



Installation

$ pip install pyblish-qml

Test out the installation with..

$ python -m pyblish_qml --demo



Usage

In any of the supported hosts, call show().

import pyblish_qml
pyblish_qml.show()

First you need to tell QML where Python and PyQt5 is.

from pyblish_qml import api, show

# Tell QML about dependencies
api.register_python_executable("C:/Python27/python.exe")
api.register_pyqt5("C:/modules/python-qt5")

show()

Alternatively, you may use environment variables instead.

$ set PYBLISH_QML_PYTHON_EXECUTABLE=c:\python27\python.exe
$ set PYBLISH_QML_PYQT5=c:\modules\python-qt5
$ maya  # for example..

Keep in mind that you don't have to register PyQt5 unless the Python executable you register isn't able to find it on its own. Also keep in mind that the directory you need to register is the parent directory of the PyQt5 Python package.

Either way, once QML is aware of where dependencies are, you may register it with pyblish-base and have it appear automatically in file-menus of software, like with pyblish-qml.

from pyblish import api
api.register_gui("pyblish_qml")

See pyblish-maya for an example.

Additional Environment Variables

  • PYBLISH_QML_MODAL=1 Block interactions to parent process, useful for headless publishing where you expect a process to remain alive for as long as QML is. Without this, Pyblish is at the mercy of the parent process, e.g. mayapy which quits at the first sign of EOF.



Documentation

Below is the current and full documentation of QML.


Supported Hosts

These are the hosts automatically recognised by pyblish-qml.

  • Maya
  • Nuke
  • Houdini
  • Hiero

Data

Some data within each Instance and Context are special to QML.

Member Applies to Behavior
publish Instance The on/off state of the toggle.
label Context/Instance Draw this instead of an instance's name
comment Context Display and edit comment in GUI

Perspective

Dive into any item to find a curated list of data related to a particular item.


Order

The order in which items are listed in the interface is a representation of how they are about to be processed. The top-most item processes first, and the bottom-most item processes last.

You can control the order by modifying the order attribute.


Optional

Plug-ins can be made optional by adding a particular attribute to your plug-ins.

class MyPlugin(...):
   optional = True

When a plug-in is optional, an artist may choose whether or not it should perform any processing.


Plug-in documentation

image

Provide your users with thorough information of what to expect of a plug-in.

Pyblish QML visualises documentation per-plugin, here are some best practices for writing it along with technical information about how the data is parsed before being displayed.

Purpose

The following are some guidelines to adhere to when writing documentation for your plug-in, but are in no way mandatory nor have any effect on the operation of Pyblish or Pyblish QML.

  1. Provide a general understanding of what the plug-in is doing.
  2. In case of a validator, propose general solutions and best-practices for how to avoid failing.
  3. Do not provide specific solutions; save those for Exception messages.

Behaviour

Documentation is taken from the __doc__ member of your plug-in class.

class MyValidator(...):
   """General description

   Longer description here.

   """

As per PEP08, the first line of the above docstring is treated as a summary of the below description and used in the GUI right after drawing the name of the plug-in.

image

The longer portion is then shown when expanded.

image

If a line should be too long to display in the GUI, the end of it is elided.

Parsing

Before showing the docstring, it is parsed. Parsing is currently very straightforward and operates on two rules.

  1. Remove all newlines
  2. Keep paragraphs

This happens so as to ensure that the maximum amount of space is used in the GUI and to get rid of the leading tabs present in any docstring.

Which means that this...

class MyValidator(...):
   """General description

   Longer description
   here.

   """

translates into..

General description

Longer description here.

Caveats

As a side-effect of the above two rules, you cannot make lists or other entries that depend on newlines.



Log messages

Provide users with information about what happens during the processing of a plug-in.

Logging uses the Python standard library logging module and is visualised graphically by its 5 levels of severity.

  1. Debug
  2. Info
  3. Warning
  4. Error
  5. Critical

Each produced via it's corresponding call to self.log within a plug-in.

class MyValidator(...):
    ...
    def process(...):
        self.log.debug("e=mc^2")
        self.log.info("Processing instance..")
        self.log.warning("Something may be wrong..")
        self.log.error("Something's *definitely* wrong!")
        self.log.critical("Call the president!")

Each level is then represented by its unique color, starting from Blue moving into Red.

Details

A log message may be short or span multiple lines. Only the first line is visualised unless an item is expanded. Once expanded, similar rules apply to parsing as the parsing of docstring (See Plug-in Documentation for more information.

  • Short version

image

  • Expanded version

image

Example

image



Exception messages

Provide users with specifics about why a plug-in failed.

Exception messages are logged when exceptions are raised by plug-ins and are designed for describing the exact resort to take when plug-ins fail.

Contrary to Plug-in Documentation, Exception Messages may get very specific about a problem, such as naming items in a host relevant to the error, or point to a particular portion of the documentation.

Behaviour

As with Log Messages, the first line of the message is shown by default, subsequent lines are hidden until expanded and follow the same formatting rules as Plug-in Documentation.

raise ValidationError("""This is a long message

And this will appear once expanded.

""")

Pro tip: It's considered good practice to include as much information as is needed here, this is where users are meant to go for specifics about what to do about a particular problem.

Example



Settings

Customise Context label and Window title.

from pyblish_qml import settings
settings.WindowTitle = "My Title"
settings.WindowSize = (430, 600)
settings.WindowPosition = (100, 100)
settings.ContextLabel = "The World"
settings.HiddenSections = ["Collect"]

Each setting is applied when the GUI is shown, which means you can change them any time before then, including between subsequent runs.

Alternatively, set context label during processing.

class CollectContextLabel(pyblish.api.ContextPlugin):
  order = pyblish.api.CollectorOrder

  def process(self, context):
    context.data["label"] = "The World"

The GUI will read the current label after having processed all collectors. Any change after Collection will not be visible in the GUI.




Differences to Pyblish Lite

Pyblish QML fills the same gap as Pyblish Lite, with a few notable differences.

Pros

  • Asynchronous operation - use the GUI during intense processing
  • Smoother visuals - animations galore
  • Inspect individual items - tens of instances, hundreds of plug-ins? no problem
  • Filter terminal via keyword search - thousands of log entries? no problem

Cons

  • Requires PyQt5 (and either Python 2 or 3)

Development wise, Pyblish QML is written in.. you guessed it, QML. Whereas Pyblish Lite is written using classic widgets. QML is a new graphical user interface language for OpenGL developed by the same group, Qt.




Testing

Tests are automatically run at each commit to GitHub via Travis-CI. You can run these tests locally via Docker too.

$ git clone https://github.com/pyblish/pyblish-qml.git
$ cd pyblish-qml
$ . build_docker.sh  # Only needed once
$ . test_docker.sh
# Doctest: pyblish_qml.models.Item ... ok
# Doctest: pyblish_qml.util.ItemList ... ok
# Reset works ... ok
# Publishing works ... ok
# ...
# util.chain works with lambdas ... ok
# 
# ----------------------------------------------------------------------
# Ran 20 tests in 1.430s
# 
# OK

If you don't have Docker available you can test with these commands, for both Python 2 and Python 3:

$ cd pyblish-qml
$ python -m nose --verbose --with-doctest --exe --exclude=vendor

pyblish-qml's People

Contributors

bigroy avatar coyode avatar darkvertex avatar davidlatwe avatar felixonmars avatar hannesdelbeke avatar jasperges avatar jboisvertrodeofx avatar jedfrechette avatar larsbijl avatar linez69 avatar liorbenhorin avatar mottosso avatar nasefbasdf avatar renaudll avatar rlessardrodeofx avatar sky123c avatar tokejepsen avatar yamahigashi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyblish-qml's Issues

Markdown for plug-in documentation

Goal

Provide for nice user-facing documentation of plug-ins.

Implementation

Documentation in the GUI is currently displayed in it's corresponding Properties Panel.

untitled

Which is coming in from the plug-ins __doc__ (doc-string) attribute.

Have a look at this information being formatted as Markdown.

PEP08

One immediate problem of this is that doc-strings would no longer conform with PEP08.

class ValidateCrocodileScales(...):
    """
Scales must face *north*, and be of equal length.

Reference
-------------

See here for more information.

- http://google.com
- [Google](http://google.com)

"""

As an alternative, we could split the responsibility into a dedicated attribute markdown and when this attribute does not exist revert back to using non-Markdown formatted text.

# Standard text
class ValidateCrocodileScales(...):
    """Scales must face north, and be of equal length"""

Versus:

# Markdown
class ValidateCrocodileScales(...):
   markdown = """Scales must face *north*, and be of equal length"""

Prevalence

In case we choose to support multiple pre-processors; Re-Structured Text, Plain and Markdown, should we then provide for three methods of input - docstring, markdown and rst properties? In that case, which wins in cases where all of them exists? Does it make sense?

Alternatively, we could provide a single doc attribute of a default format (markdown) and an additional doc_format attribute for specifics; or a hash-bang.

doc = """markdown
This is my beloved *markdown* string
"""

doc = """rst
This is my `beloved`_ string.

`beloved`_: http://google.com
"""

Discussion

Perhaps the more real question is; does it matter whether plug-ins conform with PEP08?

I'd say yes; it can be quite beneficial to reap the benefits of Sphinx and what not when it comes time to document plug-ins and have them align with documentation for other Python code. It is perhaps less relevant than other Python code, as they would possibly be read only by Pyblish and plug-in developers, and not by end-users i.e. artists.

Additionally, by separating plug-in documentation and class documentation, we effectively make room for two audiences; one is the end-user who only wishes to know how to fix the problem caught by a plug-in and the other is the developer who wishes to better understand the implementation so as to maintain it.

Pre-load

Motivation

Running a separate process means re-doing some of the work already done by some hosts; such as Autodesk Maya and The Foundry Nuke.

  1. Launching Python
  2. Initialising Qt

In more constrained environments where Pyblish QML and it's associated libraries may reside on a network drive, this means an added ~100 mb of traffic per instantiation of Pyblish QML. As the target audience is in high-end visual effects and games - where traffic typically peaks in the 500-2000 mb/sec range - the restriction is assumed to not matter. But there are still environments where a slow network is in place, causing Pyblish QML to take an unacceptable amount of time (>2 seconds) to launch.

Goal

To eliminate the time taken to start-up a separate process and load libraries.

Implementation

At the moment, launching Pyblish QML as a separate process is a matter of:

Action Size Time (300mb/sec) Time (30mb/sec)
Python 20mb 60 ms 600 ms
Import (Qt) 50mb 160 ms 1600 ms
Import (others) 5 mb 250 ms 2500 ms
Instantiation 20mb 150 ms 150 ms
Total 95 mb 620 ms 6200 ms

To remedy the time taken for these processes to finish; we'll pre-load a Python interpreter and import the required libraries upon start of a host, such as Autodesk Maya.

The pre-loaded Python interpreter would lie quietly and listen for an incoming call to wake up. The wakeup call would take the form of a http request, which is already used for general communication internally within the process; between Python and QML.

Solutions

Let's have a look at high-level solutions.

1 - Bundle

We bundle all of Pyblish QML into a single executable using Pyinstaller and distribute it. It'll run wherever anyone chooses to store it, without dependencies, pip or git.

+ Easy installation
- Not necessarily faster; the same amount of data is
  still loaded
- Difficult maintenance; we'll need to produce binaries 
  for each public-facing commit.

2 - Pre-Load File Copy

Upon loading a host:

  1. Copy a pre-made repository into the users /temp directory
  2. If it already exists, copy only program data; no binaries

Binaries consume the vast majority of space and never change.

+ As fast as local
+ No change required in deployment
- Perceived dirtiness of file-copying
- Updating source requires restart of host
- GUI still slow when launched standalone
- Occupy space on local machine (~100mb?)

3 - Pre-Load Memory

Upon loading a host:

  1. Load a Python interpreter, launch the GUI, but keep it hidden.
  2. Upon user-launch of the GUI, show it.
+ Fastest
+ No change required in deployment
- Updating source requires restart of host
- GUI still slow when launched standalone
- Memory occupied (~50mb?) regardless of user starting GUI

Killing

Currently, when a host quits, the GUI is to be killed. This is currently implemented in the integrations, such as Pyblish Nuke, and works well. But not for some. For some, the GUI remains open and must be closed manually; thus permanently terminating the process.

If the process is window-less, as it would be in this case, we'll need to find a more reliable method of killing the child-process upon termination of the parent (host) process.

Pretty-print family names

Goal

When printing family-names, offer an option to use a pretty-printed version of it.

# E.g.
myFamily -> My Family
writeNodes -> Write Nodes

However, as family names are useful for debugging, it needs to be an option to the user.

Implementation

Assume family-names are always mixedCase.

# E.g.
assert " " not in family
assert family[0] != family[0].upper()

Checkboxes too small

It's tricky to know whether a checkbox is clickable or not, maybe add hovering feedback, and/or make them bigger?

Repair

Add missing feature, to trigger a plug-in's repair functionality.

Dynamically update Interface with new instances

The instances appearing in the GUI are the ones that were available when the Pyblish tool was ran. I think that it would be great if the contents were dynamically updated based on changes done in the scene. I'm thinking of the following situation:

An artist got some feedback when trying to publish. He/she does not close the window and do some changes to the scene. Then comes back to the GUI, but it is not displaying information of new instances yet and it would require to re-open the interface to see those.

Instances toggled off by default

They should be on.

The current default is that they respond to data on an instance called publish which is basically a question. publish? If this doesn't exist, or is set to false, it will assume that you don't want it published.

publish?

  • True = Yes
  • False = No
  • Doesn't exist = No

What should happen instead is:

publish?

  • True = Yes
  • False = No
  • Doesn't exist = Yes

Convenience Toggles

Goal

Allow for quick access to checking/un-checking validations, based on some logical predicate.

  1. Toggle all
  2. Toggle none
  3. Toggle failed

Include Selectors in Terminal

Goal

To include results from processing Selectors in the Terminal so as to facilitate debugging.

Previously, Selectors were run on the host prior to launching the GUI. The GUI would then reap the selected instances and send them across for processing by subsequent plug-ins, like Validators.

However, as Selectors are equally important to get right and are as capable of producing error or messages of it's own, it makes sense for them to also take part of the growing error visualisation generated by Pyblish QML.

Quirks

There are a few quirks about the approach currently.

Server Compatibility

Plug-in/Instance compatibility are currently computed within the host, right after Selection has taken place. The host then has access to all plug-ins and instances and can run them up against each other to find which are compatible. With this approach, Selection would need to happen from the GUI which means the host would no longer have access to all instances; only plug-ins.

Solution; performing filtering within the GUI.

Double Trip

Currently, a single call to a host is made, asking it to deliver Plug-ins and Selected instances. We'll now have to make two calls; one for Plug-ins and one for Instances.

Practically speaking however this is probably in our favour as it means the GUI may show up before Selection has completed. In cases where Selection is an intensive process, it'll make for a better user experience.

Streaming

Goal

To improve performance and reliability of Pyblish processing.

At the moment, QML polls Endpoint for updates during processing at an interval of 10/sec. This means that if processing takes 9 ms to process, QML will pick up and mark the process as finished 1 ms later. However, if processing takes 11 ms, QML won't know it has finished until 9 ms afterwards.

In the case of many plug-ins and instances, this adds up and causes processing to take longer than it needs to.

Architecture

By utilising the same streaming mechanism used for downloading large files, we can stream updates from Endpoint to QML. During this stream, events will be processed much like they are currently, albeit more accurately as opposed to every 10 ms, but more importantly the stream will signal a "done" state at the exact moment it has finished, resulting in little to no delay between processes.

References

Inspector View

Goal

To provide for introspection into visualised items; instances, plug-ins and the Pyblish itself. In the simplest sense, it's an attribute editor of whatever you currently have selected.

Architecture

Upon secondary-selecting an item - be it via double-click or right-click menu - provide for an alternate/additional graphical component to visualise the meta-properties of said item. Meta-properties include things such as it's name, version, any links or media such as images.

Types of items

Plug-in

When inspecting a plug-in, provide for any and all information related to the given plug-in; including version, docstring, supported families and hosts.

To the end-user, inspecting a plug-in should provide for information about what it will do and what it's criteria is (in case of a validator), in a helpful manner. Meaning, exposed as proper documentation for anyone who has never used Pyblish before and in fact has never worked at the current studio before and are seeing the message for the first time.

It is up to the plug-in developer to provide for this documentation, but the GUI should provide for enough visuals so as to properly expose whatever information is available.

Instance

In the case of inspecting an instance, provide for information about it's actual name in the host, what nodes are actually included and are about to be extracted along with a method of accessing it's parent Asset.

Asset

In the case of publishing from an existing instance, every instance has a parent Asset. Provide for the ability to inspect this asset and it's properties. This may include any and all data that was published upon creating this asset - things like comments or even a discussion thread, images, relationships to other assets and who to contact/who is the author.

System

Inspecting the system is another word for inspecting the settings of the program. This may include restarting the host server, altering the colors of the GUI (theming) or other personal settings.

User Interface

Inspecting an instance

issue5-inspector_view

When host is not found, feedback is incorrect

This one is really picky.

If the interface is run and for some reason it is not able to find a host, it is still allowing the user to press the Publish button and it says that No Instances were found. I think that for the sake of clarity, the button should be disabled and have a message clearly visible that states that Host not found

Does that sound feasible?

Resource System

Goal

Use the Qt Resource System to remove the dependency of file system paths and to improve start-up and running times.

The Qt Resource System packages all data (e.g. images and QML files) into a single compressed Python library. The root QML document is then linked to via a special prefix; qrc:// whereas all subsequent files are relative this path.

The benefit of doing this is that related files are loaded into memory in a single batch and thus accessed faster.

Visualise path to plug-in

Goal

As suggested by @davidmartinezanim, include a path to plug-ins so they are easier to find in case maintenance is required.

Perhaps in the property panel?

Toggle Plug-In

Goal

To allow for optional plug-ins to be toggled on/off.

User Interface

Optional plug-ins display a checkbox next to itself. When de-toggled, it fade out into the background, similar to when it shows incompatibility with a particular instance, as per #3.

issue4-toggle_plugin

Feature to define custom Python folder

I think that it might be worth adding functionality that allows to define a custom Python folder to be used by Pyblish-QML. At the moment, it will use the system's default and there might be some instances in which this is not desired.

Let's say that a company wants to use another version of Python as their default since much of their code base relies on it. Having another version of Python of the system is not a problem but we don't want to force people to make the one we expect the default one.

Instead, it would be good to have be able and pass a custom path for Pyblish to use. If no custom folder has been defined, then it could use the system's.

Just to make the system more flexible.

UI doesn't show plugin list upon loading

I've noticed that when I open the UI, the list of plugins does not show up. When that happens, resizing the window forces the interface to re-draw and show the plugin names.

I think that the reason is the amount of plugins - This is the only thing that changed for me in the last few days

Application Debugging Information

Goal

To visualise information related to:

  1. The GUI
  2. Pyblish
  3. and Host

At the moment, our needs are small and circulates mainly around the need to visualise with which host we communicate along with it's version.

User Interface

Visually, this may suffice.

issue2-system_information

In which the left-hand numbers are the version of Pyblish, as exposed via Endpoint from the given host, which is visible on the right-hand side, along with a unique numbering/name representing the instance of the particular process; as a user may have multiple instances of Maya running at the same time.

Run Individual Plug-In

Goal

To facilitate precise testing of individual aspects of an asset to qualify for the standards set forth by the organisation.

This may be useful in cases where a user is aware of potential mishaps in his asset and would like to run it through the test, without actually publishing, and without running it through other tests that may either certainly fail or succeed without surprise.

Architecture

Given the architecture laid forth in #7, executing an individual plug-in on an individual instance is a no-brainer and builds on the very same logic, but without starting an event-loop.

User Interface

issue8-individualplugin

Installer

Goal

Eliminate the PyQt5 installation hassle.

Implementation

Bundle Pyblish QML and any dependencies into an installer using.

  • Pyinstaller
  • InnoSetup

Resulting in a standalone executable.

c:\pyblish-qml\pyblish.exe

API Compatibility

Pyblish QML (PQ) can run without a host but the current use-cases all involve an integration. PQ will come embedded with knowledge about where it is connecting - i.e. the server-side API - and for things to work seamlessly these APIs must match.

 ________          __________
|        |        |          |
|   PQ   <--------> Endpoint |
|   1.0  |        |    1.0   |
|________|        |__________|

For the end user, this means Pyblish QML may launch successfully, only to try and communicate with a host running an incompatible version of the API.

API Versioning

One way of solving this dilemma is to introduce API versioning on both sides; server declares and client interprets.

For example, the server may be running 1.0.3 whereas the client may support [1.0.1, 1.0.2, 1.0.3]. Upon connecting, the server transmits it's running version at which point the client may decide whether or not it is supported.

The inherent problem of API versioning is of course the added maintenance.

We now have the initial abstraction of client/server, added with an additional layer of API compatibility.

1.0 + 1.0?: true
1.0-api1.0 + 1.0-api1.0?: true
1.0-api1.0 + 1.0-api1.2?: true

Versioning A

We could introduce an additional layer of versioning just for the API.

API: 1.0
  - pyblish-endpoint 1.0
  - pyblish-endpoint 1.1
  - pyblish-endpoint 1.2
API: 1.1
  - pyblish-endpoint 1.2.1
API: 2.0
  - pyblish-endpoint 2.0

In this way, we are free to make updates to Pyblish Endpoint that does not break it's interface and retain compatibility with PQ. The downside being an additional level of versioning to keep track of.

Versioning B

We could utilise the existing version of Pyblish Endpoint as baseline for its API.

pyblish-endpoint: 1.1.7
api: 1.1.7

At which point PQ signals support for versions, via iscompatible

api>=1.1.4, <=1.1.7

The disadvantage of this approach however is that PQ will require and update for updates of Pyblish Endpoint even though the interface may not have changed, resulting in needless recompilations of the installer.

We could solve this by not considering patch releases, and instead only consider major and minor updates as breaking.

api>=1, <2  # Any version between 1.0.0 and 2.0.0, not including 2.0.0

API Support

On the other end of the rainbow we've got PQ that needs to provide support for the API. We could implement this in one of two ways.

  1. One-to-one: Any version of PQ is only compatible with any one version of the API
  2. One-to-many: PQ supports ranges of the API
# One-to-one
 _______          _______
|       |        |       |
|  1.0  <-------->  1.0  |
|_______|        |_______|


# One-to-many
 _______          _______
|       |        |       |
|  1.0  <-------->  1.0  |
|_______|        |  1.1  |
                 |  1.2  |
                 |_______|

Of course one-to-many is the ideal candidate from an end-user point of view as it would allow them to make updates to one but not necessarily the other, but it does put additional burden onto development.

API Support Abstraction

A naive approach for one-to-many support of an API could come in the form of conditional logic.

if endpoint.version == "1.0":
   # do this
if endpoint.version == "1.1:
   # do that

But this would cause the codebase to grow sporadically and indefinitely as more and more versions enter the arena. A more sustainable approach may be to abstract the version into a separate module.

endpoint.py

if endpoint.version == "1.0":
   from endpoint_1_0 import *
if endpoint.version == "2.0":
   from endpoint_2_0 import *

At which point each versioned API module provide an implementation matching the corresponding version of Pyblish Endpoint with a common interface.

endpoint_1_0

def process(...):
    old_way_of_doing_things()

endpoint_2_0

def process(...):
   new_way_of_doing_things()

But be used without special regard from within the PQ implementation.

app.py

import endpoint

endpoint.process(plugin, instance)

Conclusion

Clearly the work involved in providing an installer is not to be taken lightly, but it does require solving of API versioning and compatibility which is bound to show up in other areas as the libraries and userbase grows. No to mention the work involved in actually bundling with Pyinstaller or packaging with InnoSetup which I left out due to having enough previous experience with both to know that it is possible and how to go about setting up.

Customizable menus for validate and publish

I suppose that this will be an easy one.

Is it possible to get rid of the menus validate and publish that we get by default and implement our own. For example, in my case, I would rather not have anything that runs on the command line as it is not user friendly for a lot of the artists. Because of that, I would only leave the one that runs the UI.

In addition to that, I'd like to have a menu somewhere else on my interface so we can keep it organized along with some other tools that we have in-house.

If any of the information is unclear, let me know and I will try to elaborate

Processing Feedback

Goal

To provide the user with an overview of the current processing; including which plug-in is currently operating and which instance it is operating upon.

Architecture

We'll take over the pyblish.main.publish() event-loop and implement it in Javascript where it can be accessed by our GUI.

In a nutshell, these activities are involved.

  • Requesting the execution of a single plug-in, processing a single instance
  • Receiving feedback during processing of a single instance
  • Receiving completion status

POST /process

Executing a single plug-in on a single instance is implemented in Endpoint and service from which it may be accessed by the GUI.

GET /process/<id>

Receiving feedback is a little more involved, because Endpoint has no way of contacting the GUI unless the GUI has first initiated contact and is awaiting a response (classic response/request). So, real-time feedback will instead be accomplished via polling.

It will involve the service storing received logging messages from Pyblish during execution in a Python Queue. QML will then, upon regular intervals (such as every 0.5 seconds) request for this Queue to be emptied. As the queue will run on a separate thread, it may be accessed even though Maya may be busy with other things (I think) and requests shouldn't be interfering with performance in any noticeable amount.

Upon Completion

Spontaneously, we could simply listen in on the return message from our POST request above. But wait, we can't do that.

For one, we need a response before we can start asking questions about the currently running process. The communication would go something like this.

>> Process PluginA for InstanceA, please.
<< Ok, here's the ID of this process, in case you need to ask about it: <someId>
...
>> Regarding <someId>, how is that going?
<<  It's currently running, here are a few messages in the Queue. [message1, message2]
...
>> Regarding <someId>, any new messages?
<< Still running, and yes actually. Here you go. [message3, message4]
...

Now here comes the interesting part. For a completion message, we'll rely on the same mechanism. But this time, the response will be different.

...
>> Regarding <someId>, how is that going?
<< It's done, here are the latest messages, and a completion status.

User Interface

issue7-processing

Make terminal selectable

It would be great if we could change the way the terminal behaves.I would week mouse wheel to move up and down. Having said that, instead of left click to do the same, I would use right click. (leaving left click for selection of text).

That would make easier to copy contents of the terminal and send them through email or accessing an URL.

Would that be feasible?

Logging filter in the terminal tab

Do you think it would be worth to add an option to filter the different logging levels?

Some of the plugins I'm doing print the current file being validated and the scenes have a lot of those. When I want to focus on the errors, it kind of clutters the view as I get all the info logs. Having said that, they are useful when it comes to make sure that the plugin is going through all of those.

Horizontal scrollbar in the Terminal

Is it worth adding an horizontal scrollbar in the terminal apart from a vertical one? That would prevent lines from jumping down (which sometimes makes difficult to read the output).

Plug-in Groups

Goal

To visually distinguish plug-ins that perform similar processing so as to make them easier to find.

E.g.

  • mesh validations
  • uv validations
  • metadata extractors
  • filesystem extractors

Implementation

Associate an attribute with each plug-in to look for from within the UI, such as category. The UI may then visually nest each plug-in under each corresponding category, similar to how it currently works for Instances and their corresponding family attribute.

class MyPlugin(...):
    category = "uv"

Visualise Plug-In Compatibility

Goal

To help the user understand which plug-ins will process a particular instance.

Architecture

Upon selecting an instance, make it apparent as to which plug-ins are about to process the instance.

User Interface

Upon selecting an instance, incompatible plug-ins fade into the background.

issue3-plugin_compatibility

State

Goal

Facilitate changes being made to data in GUI.

At the moment, data is read from a host (e.g. Maya) and sent to QML. But it is never returned.

That's allright as we currently can't modify the data. But we want to be able to, which means we'll need a method of sending the modified data back to the host.

The same goes for toggling instances. A toggled instance either has no publish data member, or it exists but is set to False.

Toggling an item must create this attribute and set it to True. And this data must also be sent back to the host.

State

The state consist of everything visualised by a GUI, including data that may be modified.

When the time comes to publish, the entirety of the state is sent back and used to re-create the state from the GUI in the host prior to publishing; like which items are toggled, any modified instance data etc.

 _________                _________
|         |   initial    |         |
|  State  |-------------->         |
|_________|              |         |
                         |   Gui   |
 _________               |         |
|         |   modified   |         |
|  State  <--------------|         |
|_________|              |_________|

Implementation

Distil all that passed over-the-wire into a single data-structure; a JSON-serialisable dictionary. The dictionary is then (optionally) altered from within the GUI and sent back to be de-serialised.

Example data structure

{
  "context": {
       "data": 
           {
               "key": "value"
           },
       "children": [
           {
               "name": "MyInstanceA",
               "objName": "plugin_SEL",
               "children": [],
               "data": {}
           }
       ]
  },
  "plugins": [
    {
       "name": "PluginA",
       "version": [0, 1, 0],
       "family": "myFamily",
       "category": "Mesh",
       "requires": ">=1.0.2",
       "order": 1,
       "absoluteOrder": 0,
       "optional": true,
       "doc": "Description",
     },
  ]
}

Displaying results of a Publish

What's the plan to display information about the results of a Publish (Whether it succeed or failed).
I'd love to see that information within the same interface. Maybe in a Results or Output tab.

Also, I can't stress enough how much I would like to have the option to spit that into a text file as well so I can have that information available outside of Pyblish (or the host for that matter).

Commenting and "Are you sure?"

Goal

Provide an option for users to enter an optional comment, may be mandatory or may never appear based on studio-wide settings.

Additionally, with or without commenting, provide for a safety; preventing users from accidentally publishing.

User Interface

issue9-commenting

Window Icon

There is currently no window icon for the application; it's showing the Python logo.

Splash Screen

Goal

To provide users with a sense of immediate feedback.

Currently, the GUI is very small, yet it takes about 2 seconds for anything to appear on screen (Windows, on Ubuntu the time is half that for some reason).

Architecture

Utilise the feature of QML which allows for components to be dynamically loaded so as to allow light items to appear first, keeping the user company, while the rest of the GUI is computed and finally displayed. Once the component has been loaded, listen in on the signal and from there trigger the animation to "unfold" the interface.

User Interface

Provide part of the final interface as something for the user to look at while awaiting full functionality.

issue6-splash

Resize "Instance" and "Plugins" sections in the main tab

The main tab is divided in two parts:

  • Instances
  • Plugins

At the moment it is not possible to adjust the size of each of those sections. I think that there will be some instances in which the name of the instances will be quite long and they will not fit the space that it is currently allocated for them.

Would it be possible to have a way to resize (manually or automatically) each section?

Parent window to host

Currently, the GUI is launched as a separate window, but we'd like it to appear as though it was a child of to the host.

This may require OS-specific commands.

On Windows, SetParent seems the obvious winner, though it seems to have some warts.

Something like this ought to do it for Maya on Windows.

from PySide import QtGui

widgets = dict((w.objectName(), w) for w in QtGui.QApplication.topLevelWidgets())
window = widgets['MayaWindow']
id = window.winId()

import ctypes
ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]

int_hwnd = ctypes.pythonapi.PyCObject_AsVoidPtr(id)

If a similar feature is available in Linux distributions (Wayland?) then that's where we'll go.

Map ESC to Stop

Goal

When the user hits the ESC key, stop processing. This should be the same action as when the user hits the stop key during processing.

Could not find or load the Qt platform plugin "windows".

This application failed to start because it could not find or load the Qt platform plugin "windows".

Available platform plugins are: minimal (from Z:\python-qt5\PyQt5\plugins\platforms), offscreen (from Z:\python-qt5\PyQt5\plugins\platforms), windows (from Z:\python-qt5\PyQt5\plugins\platforms).

Reinstalling the application may fix this problem.

As reported by @davidmartinezanim, this sometimes occur when running the following.

>>> import pyblish_maya
>>> pyblish_maya.show(console=True)

Property panel docstring

Goal

As reported by @davidmartinezanim, finesse the look of the doc-string in the property panel.

We'll also need proper wrapping; in which case we'll need to discard new-lines coming from the original text, making explicit formatting a little more tricky for the developer. For instance, you won't be able to decide where new-lines appear.

This is how Click does it, for instance.

In addition, we'll want to de-duplicate the doc-string from the documentation and doc data member.

Hyperlinks in Output

I think that it would be nice if the output panel had some kind of rich formatting.

I don't think that we need anything overly complex. Having said that it would be great if any URLs are converted into hyperlinks that can be clicked (triggering default browser and such).

When a Publish fails, I want to provide the artist not only with a message but a link to a WIKI page explaining what needs to be done to get the plugin to succeed. This kind of training is specially useful for new starters that are not familiar with the pipeline.

I other words, it would help us empowering artists.

No Connection in Maya 2013

Reported by @davidmartinezanim, GUI reports a No Connection when run from Maya 2013 and a console message indicating an error while connecting.

module QtQuick is not installed

image

As reported by @davidmartinezanim, this can sometimes occur when running the GUI. It looks to be related to the PyQt5 installation.

Tooltip

Implement a tooltip, similar to Bootstrap, as illustrated in #8

Startup delay

The GUI currently takes a second or two before anything shows up. This is a bug.

Closing host while the interface is open

At the moment, if the interface is open and you close the host, the interface will remain open but it will lose the connection with the host. I think that in those situations, we should either close the interface or provide some kind of feedback to the user so he can hook up the interface with other currently active hosts.

Multiple Instances

Goal

Allow the frontend to communicate with multiple endpoints.

Architecture

At the moment, the frontend is hardcoded to only speak with frontends at port 6000. The only implemented host so far (Maya) is then also hardcoded to provide an endpoint at this address.

So, provide an option for launching the frontend using a custom port.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.