Skip to content

Merge Context Manager + Work Files (Fix #412) #442

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

Merged
merged 36 commits into from
Feb 17, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6ae6742
Work in progress of Context Manager + Work Files merge (WIP)
BigRoy Sep 6, 2019
ecf15b1
Preserve last active task in TaskWidget as asset is switched
BigRoy Sep 9, 2019
94b317e
Refactor NameWindow code according to contribution guidelines
BigRoy Sep 9, 2019
5d0b923
Set parent for NameWindow and fix FramelessWindowHint flags
BigRoy Sep 9, 2019
0c9a5c2
Include icons for breadcrumbs, log warning on missing work root path
BigRoy Sep 10, 2019
8d84544
Update to latest avalon core master
BigRoy Sep 10, 2019
eb5f152
Use def as opposed to assigning a lambda expression
BigRoy Sep 10, 2019
b76a1ae
Refactor `list` to `file_list` to avoid shadowing built-in `list`
BigRoy Sep 10, 2019
7b8499d
First declare widgets to self.widgets in NameWindow, match Window code
BigRoy Sep 12, 2019
cef2880
Merge branch 'master' of https://github.com/getavalon/core into fix412
BigRoy Dec 17, 2019
7ad657a
Improve merge of Context Manager and Work Files tool
BigRoy Dec 17, 2019
af1917f
Remove double Window initialization
BigRoy Dec 17, 2019
bb05974
Fix missed refactor to self._get_session
BigRoy Dec 17, 2019
051cb99
Correctly only return changes that actually changed
BigRoy Dec 17, 2019
238809c
Only update current task on double click if it's not current context
BigRoy Dec 17, 2019
c3d0b7d
Fix save current file prompt not showing up because of parenting
BigRoy Dec 17, 2019
e60e306
Log error when user wants to save current file without name on scene …
BigRoy Dec 17, 2019
d713043
Work files: add date modified, use model->view, duplicate to context …
BigRoy Dec 22, 2019
9bc0164
Remove redundant flags() method for FilesModel
BigRoy Dec 22, 2019
83617b6
Fix undefined work_dir and scene_dir variables
BigRoy Dec 23, 2019
2f4aa80
Add comment why we are parsing Maya workspace.mel manually
BigRoy Dec 23, 2019
3d7c65e
Code cosmetics (PEP8)
BigRoy Dec 23, 2019
0aa7781
Implement "Create Work Area" for Work Files + Clean up code
BigRoy Jan 6, 2020
0617307
Remove on_task_pressed functionality
BigRoy Jan 6, 2020
b7b95fd
Cleanup code
BigRoy Jan 6, 2020
050f442
Change code style (try to shush the Hound)
BigRoy Jan 6, 2020
ff30979
Allow Work Directory creation in Work Files tool on Save As
BigRoy Jan 6, 2020
acf5886
tasks model show `Tasks` instead of `name`
iLLiCiTiT Feb 11, 2020
ee1ae65
Do not show context menu if Item is not enabled
iLLiCiTiT Feb 11, 2020
be07276
removed contextmanager from hosts
iLLiCiTiT Feb 11, 2020
bc8ef09
added view for FilesWidget to catch only left mouse button double click
iLLiCiTiT Feb 11, 2020
78be136
Merge pull request #3 from pypeclub/fix412_pype_variant_2
BigRoy Feb 11, 2020
63e7d4c
added context item to avalon menu
iLLiCiTiT Feb 11, 2020
48c362d
fixed houdini context label
iLLiCiTiT Feb 13, 2020
43b60c1
addde separator to nuke menu
iLLiCiTiT Feb 13, 2020
297824d
Merge pull request #5 from pypeclub/fix412_context_label
BigRoy Feb 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions avalon/fusion/workio.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ def current_file():
return current_filepath


def work_root():
from avalon import Session
def work_root(session):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Each Work files API now requires session for the work_root to be able to compute the Work Root for a non-active Session object (e.g. not api.Session)


work_dir = Session["AVALON_WORKDIR"]
scene_dir = Session.get("AVALON_SCENEDIR")
work_dir = session["AVALON_WORKDIR"]
scene_dir = session.get("AVALON_SCENEDIR")
if scene_dir:
return os.path.join(work_dir, scene_dir)
else:
Expand Down
7 changes: 3 additions & 4 deletions avalon/houdini/workio.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ def current_file():
return current_filepath


def work_root():
from avalon import Session
def work_root(session):

work_dir = Session["AVALON_WORKDIR"]
scene_dir = Session.get("AVALON_SCENEDIR")
work_dir = session["AVALON_WORKDIR"]
scene_dir = session.get("AVALON_SCENEDIR")
if scene_dir:
return os.path.join(work_dir, scene_dir)
else:
Expand Down
31 changes: 24 additions & 7 deletions avalon/maya/workio.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,27 @@ def current_file():
return current_filepath


def work_root():

# Base the root on the current Maya workspace.
return os.path.join(
cmds.workspace(query=True, rootDirectory=True),
cmds.workspace(fileRuleEntry="scene")
)
def work_root(session):
work_dir = session["AVALON_WORKDIR"]
scene_dir = None

# Query scene file rule from workspace.mel if it exists in WORKDIR
workspace_mel = os.path.join(work_dir, "workspace.mel")
if os.path.exists(workspace_mel):
scene_rule = 'workspace -fr "scene" '
# We need to use builtins as `open` is overridden by the workio API
open_file = __builtins__["open"]
with open_file(workspace_mel, "r") as f:
for line in f:
if line.strip().startswith(scene_rule):
remainder = line[len(scene_rule):] # == "rule";
scene_dir = remainder.split('"')[1] # == rule
else:
# We can't query a workspace that does not exist
# so we return similar to what we do in other hosts.
scene_dir = session.get("AVALON_SCENEDIR")

if scene_dir:
return os.path.join(work_dir, scene_dir)
else:
return work_dir
11 changes: 8 additions & 3 deletions avalon/nuke/workio.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ def current_file():
return os.path.normpath(current_file).replace("\\", "/")


def work_root():
from avalon import Session
return os.path.normpath(Session["AVALON_WORKDIR"]).replace("\\", "/")
def work_root(session):

if scene_dir:
path = os.path.join(work_dir, scene_dir)
else:
path = work_dir

return os.path.normpath(path).replace("\\", "/")
108 changes: 75 additions & 33 deletions avalon/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,61 +926,103 @@ def get_representation_context(representation):
return context


def update_current_task(task=None, asset=None, app=None):
"""Update active Session to a new task work area.
def compute_session_changes(session, task=None, asset=None, app=None):
Copy link
Collaborator Author

@BigRoy BigRoy Dec 17, 2019

Choose a reason for hiding this comment

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

I've made this a new function to compute the changes to the current session required to become a new valid session. Before we only had update_current_task which did the same but would always change the active session. That computing of the required changes is now moved to this separate function.

We might want to come up with a better name and maybe expose it in the API?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Or not expose compute_session_changes in API, but add a new arg called dry_run=False to update_current_task ?

If dry_run set to True, then return early without update.

Copy link
Collaborator

Choose a reason for hiding this comment

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

And maybe need to add one more internal arg called _changes=None to update_current_task, so we can pass the changes that returned from compute_session_changes into update_current_task to avoid double work.

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 dry_run argument does sound like a decent alternative to having this in a separate function. @mkolar @mottosso any preference on this one? Separate functions like this or make one and add dry_run argument?

I'm not too big a fan of adding the _changes internal argument. It seems like a premature optimization that for now seemingly adds redundant complexity.

"""Compute the changes for a Session object on asset, task or app switch

This updates the live Session to a different `asset`, `task` or `app`.
This does *NOT* update the Session object, but returns the changes
required for a valid update of the Session.

Args:
task (str): The task to set.
asset (str): The asset to set.
app (str): The app to set.
session (dict): The initial session to compute changes to.
This is required for computing the full Work Directory, as that
also depends on the values that haven't changed.
task (str, Optional): Name of task to switch to.
asset (str or dict, Optional): Name of asset to switch to.
You can also directly provide the Asset dictionary as returned
from the database to avoid an additional query. (optimization)
app (str, Optional): Name of app to switch to.

Returns:
dict: The changed key, values in the current Session.
dict: The required changes in the Session dictionary.

"""

mapping = {
"AVALON_ASSET": asset,
"AVALON_TASK": task,
"AVALON_APP": app,
}
changed = {key: value for key, value in mapping.items() if value}
if not changed:
return
changes = dict()

# Update silo when asset changed
if "AVALON_ASSET" in changed:
asset_document = io.find_one({"name": changed["AVALON_ASSET"],
"type": "asset"})
assert asset_document, "Asset must exist"
changed["AVALON_SILO"] = asset_document["silo"]
# If no changes, return directly
if not any([task, asset, app]):
return changes

if task:
changes["AVALON_TASK"] = task

if app:
changes["AVALON_APP"] = app

# Update silo and hierarchy when asset changed
if asset:
if isinstance(asset, dict):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This has now additionally been allowed to be passed a database document for an asset as opposed to only working by its name. This allows to avoid the additional query to the database.

# Assume database document
asset_document = asset
asset = asset["name"]
else:
asset_document = io.find_one({"name": asset,
"type": "asset"})
assert asset_document, "Asset must exist"

changes["AVALON_ASSET"] = asset

# Update silo
changes["AVALON_SILO"] = asset_document["silo"]

# Update hierarchy
parents = asset_document['data'].get('parents', [])
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This code has moved and fixes a BUG where previously if asset had not changed with the call then asset_document would not have been a set variable.

hierarchy = ""
if len(parents) > 0:
hierarchy = os.path.sep.join(parents)
changes['AVALON_HIERARCHY'] = hierarchy

# Compute work directory (with the temporary changed session so far)
project = io.find_one({"type": "project"},
projection={"config.template.work": True})
template = project["config"]["template"]["work"]
Comment on lines 994 to 996
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It could be worth checking whether we might want to cache this call to project because usually as you're working in a project the Work files template should be a static concept (not change during the project runs) and since we're unable to change project in-app this means this template would never change. Maybe we can cache it on the first ever call. (Optimization only)

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1, maybe cache it on App launch.

_session = Session.copy()
_session.update(changed)
changed["AVALON_WORKDIR"] = _format_work_template(template, _session)
_session = session.copy()
_session.update(changes)
changes["AVALON_WORKDIR"] = _format_work_template(template, _session)

return changes


def update_current_task(task=None, asset=None, app=None):
"""Update active Session to a new task work area.

This updates the live Session to a different `asset`, `task` or `app`.

Args:
task (str): The task to set.
asset (str): The asset to set.
app (str): The app to set.

Returns:
dict: The changed key, values in the current Session.

"""

parents = asset_document['data'].get('parents', [])
hierarchy = ""
if len(parents) > 0:
hierarchy = os.path.sep.join(parents)
changed['AVALON_HIERARCHY'] = hierarchy
changes = compute_session_changes(Session,
task=task,
asset=asset,
app=app)

# Update the full session in one go to avoid half updates
Session.update(changed)
Session.update(changes)

# Update the environment
os.environ.update(changed)
os.environ.update(changes)

# Emit session change
emit("taskChanged", changed.copy())
emit("taskChanged", changes.copy())

return changed
return changes


def _format_work_template(template, session=None):
Expand Down
5 changes: 5 additions & 0 deletions avalon/tools/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ def get_active_asset(self):
current = self.view.currentIndex()
return current.data(self.model.ObjectIdRole)

def get_active_asset_document(self):
"""Return the asset id the current asset."""
current = self.view.currentIndex()
return current.data(self.model.DocumentRole)
Comment on lines +123 to +126
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Solely added this to make it very trivial to retrieve the currently active asset's document as opposed to its name.


def get_active_index(self):
return self.view.currentIndex()

Expand Down
Loading