Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d32b18f
Refactor widgets and layouts
danbradham Jan 16, 2020
1299dd1
Moved icons
danbradham Jan 16, 2020
3be6959
Moved Frameless behavior to mixin
danbradham Jan 16, 2020
0bedc39
Remove extra import in eventloop
danbradham Jan 16, 2020
df11c30
Setup launcher app
danbradham Jan 16, 2020
8499e30
Make launcher accessible from UIManager
danbradham Jan 16, 2020
be78720
Work on header widget
danbradham Jan 16, 2020
63c972b
Add launcher ui_task
danbradham Jan 16, 2020
233d47c
Make use of __all__ in widgets
danbradham Jan 16, 2020
7d97cd7
Add HLine and VLine widgets
danbradham Jan 16, 2020
a2068e3
Add Navigation
danbradham Jan 16, 2020
f8bfd5f
Move colors to _defaults.scss
danbradham Jan 16, 2020
85efb42
Implement Header widget
danbradham Jan 16, 2020
eec0d4a
Use Glyphs and IconButtons in dialogs
danbradham Jan 16, 2020
9ed0591
Support multiple values in scale.pt and scale.px
danbradham Jan 16, 2020
8ba78d9
Use css_properties in Buttons
danbradham Jan 16, 2020
e2e3220
Fix Frameless Cursors
danbradham Jan 17, 2020
69003bb
Pass api object to Launcher App
danbradham Jan 17, 2020
d06ff1f
Update svg icons and stylesheet
danbradham Jan 17, 2020
d5aef33
Add EventLooop.quit method
danbradham Jan 17, 2020
16934be
Add system tray to launcher
danbradham Jan 17, 2020
8738c02
Add edit mode to breadcrumbs
danbradham Jan 17, 2020
86be510
Prevent Qt imports in 27
danbradham Jan 17, 2020
4e4b9ac
Improve api.show
danbradham Jan 17, 2020
f33b0d5
Fix __init__.py imports
danbradham Jan 17, 2020
93b7e76
Make sure launcher layouts have a parent
danbradham Jan 17, 2020
69ae64a
Stub out treemodel
danbradham Jan 17, 2020
4f3fee8
Fix dpi scaling of stylesheet
danbradham Jan 18, 2020
650aca8
Cache reads in fsfs
danbradham Jan 19, 2020
d7ebf3d
Add UI State class
danbradham Jan 22, 2020
0ba8d93
Add api.context_from_obj
danbradham Jan 22, 2020
3f6de0a
Add api.validate_context
danbradham Jan 22, 2020
2edebbe
Set mount from current context in io methods
danbradham Jan 22, 2020
0653710
Remove attr access from Context class
danbradham Jan 22, 2020
88d17eb
Add file cache to fsfs
danbradham Jan 22, 2020
b3e73b7
Connect navigation to app state
danbradham Jan 22, 2020
a5016e7
Move context uri methods to API
danbradham Jan 22, 2020
a71ee2f
Update focus order when state changes
danbradham Jan 22, 2020
e25a30f
Update construct font
danbradham Jan 22, 2020
ac78176
Add support for bookmarks
danbradham Jan 23, 2020
fa14fd3
Move dialogs to subpackage
danbradham Jan 23, 2020
e8e838e
Add additional Cache methods
danbradham Jan 23, 2020
4b67d58
Implement BookmarksDialog
danbradham Jan 23, 2020
67fe72d
Update compat
danbradham Jan 24, 2020
517bc42
Fix initial migration
danbradham Jan 24, 2020
8c6a887
Mount migrations to api object
danbradham Jan 25, 2020
3d9dc6e
Introduce safe_iterdir to fsfs
danbradham Jan 25, 2020
0d890bb
Launcher becomes base App object
danbradham Jan 25, 2020
60ec3cc
Tidy up Navigation and Bookmarks
danbradham Jan 25, 2020
fb50883
Finish tree Node implementation
danbradham Jan 25, 2020
1290f14
Return in get_project_by_id
danbradham Jan 25, 2020
af76356
Move create_old_project to migrations.utils
danbradham Jan 25, 2020
feddd32
Implement Sidebar Tree
danbradham Feb 3, 2020
d4dbd97
Implement ui context menus
danbradham Feb 3, 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
135 changes: 121 additions & 14 deletions construct/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
import atexit
import inspect
import logging
from functools import wraps
from logging.config import dictConfig

# Local imports
from . import schemas
from .compat import Mapping, basestring
from . import migrations, schemas
from .compat import Mapping, basestring, wraps, zip_longest
from .constants import DEFAULT_LOGGING
from .context import Context
from .context import Context, validate_context
from .errors import ContextError
from .events import EventManager
from .extensions import ExtensionManager
Expand Down Expand Up @@ -85,6 +84,7 @@ def __init__(self, name=None, **kwargs):
self.extensions = ExtensionManager(self)
self.context = Context()
self.schemas = schemas
self.migrations = migrations
self.io = IO(self)
self.ui = UIManager(self)
self._logging_dict = kwargs.pop('logging', None)
Expand Down Expand Up @@ -179,7 +179,7 @@ def uninit(self):
def get_context(self):
'''Get a copy of the current context.

.. seealso:: :class:`construct.context.Context`
.. seealso:: :class:`construct.context.Context.copy`
'''

return self.context.copy()
Expand All @@ -191,7 +191,7 @@ def set_context(self, ctx):
Set the active context permanently::

>>> new_ctx = api.get_context()
>>> new_ctx.project = 'A_PROJECT'
>>> new_ctx['project'] = 'A_PROJECT'
>>> api.set_context(new_context)

Temporarily set context::
Expand Down Expand Up @@ -231,13 +231,50 @@ def set_context_from_path(self, path):

self.context = self.context_from_path(path)

def _context_from_obj(self, obj, data):
if obj['_type'] == 'project':
data['project'] = obj['name']
project = self.io.get_project_by_id(obj['_id'])
project_path = self.io.get_path_to(project)
location, mount = self.get_mount_from_path(project_path)
data['location'] = location
data['mount'] = mount
elif obj['type'] == 'asset':
data['asset'] = obj['name']
data['bin'] = obj['bin']
project = self.io.get_project_by_id(obj['project_id'])
self._context_from_obj(project, data)

def context_from_obj(self, obj, data=None):
'''Returns a Context instance from the specific data obj.

Arguments:
obj (dict) - Project or asset data.
'''

data = {}
self._context_from_obj(obj, data)

context = Context(
host=self.context['host'],
location=self.context['location'],
mount=self.context['mount'],
**data
)
return context

def validate_context(self, context):
'''Returns True if the context is valid.'''

return validate_context(self, context)

def context_from_path(self, path):

ctx = Context(host=self.context.host)
ctx = Context(host=self.context['host'])

path = unipath(path)
if path.is_file():
ctx.file = path.as_posix()
ctx['file'] = path.as_posix()

location_mount = self.get_mount_from_path(path)
if location_mount:
Expand All @@ -252,6 +289,74 @@ def context_from_path(self, path):

return ctx

def context_from_uri(self, uri):
'''Create a Context object from an uri.

Examples:

>>> api.context_from_uri('cons://local/projects/project')
{'location': 'local', 'mount': 'projects', 'project': 'project'}

>>> api.context_from_uri('local/projects/project')
{'location': 'local', 'mount': 'projects', 'project': 'project'}
'''

# Split off uri_prefix
uri_prefix = None
if '://' in uri:
uri_prefix, uri = uri.split('://', 1)
uri_prefix += '://'

uri_parts = uri.strip(' /\\').split('/')
uri_parts_map = [
'location',
'mount',
'project',
'bin',
'asset',
'workspace',
'task',
'file',
]

context = Context(
host=self.context['host'], # Inject host from current context
)
for key, value in zip_longest(uri_parts_map, uri_parts):
context[key] = value
return context

def uri_from_context(self, context):
'''Create a Context object from an uri.

Examples:

>>> ctx = Context(
... location='local',
... mount='projects',
... project='project'
... )
>>> api.uri_from_context(ctx)
'cons://local/projects/project'
'''

uri_parts = []
uri_parts_map = [
'location',
'mount',
'project',
'bin',
'asset',
'task',
'workspace',
'file',
]
for key in uri_parts_map:
value = context.get(key, None)
if value:
uri_parts.append(value)
return 'cons://' + '/'.join(uri_parts)

def set_mount(self, location, mount):
self.update_context(location=location, mount=mount)

Expand All @@ -264,11 +369,11 @@ def get_mount(self, location=None, mount=None):
mount (str): Name of mount or context['mount']
'''

location = location or self.context.location
mount = mount or self.context.mount
location = location or self.context['location']
mount = mount or self.context['mount']
path = self.settings['locations'][location][mount]
if isinstance(path, dict):
path = path[self.context.platform]
path = path[self.context['platform']]
ensure_exists(path)
return unipath(path)
else:
Expand All @@ -294,7 +399,7 @@ def get_locations(self):
def host(self):
'''Get the active Host Extension.'''

return self.extensions.get(self.context.host, None)
return self.extensions.get(self.context['host'], None)

def define(self, event, doc):
'''Define a new event
Expand Down Expand Up @@ -395,10 +500,12 @@ def unextend(self, name):
else:
_log.debug(name + ' was not registered with api.extend.')

def show(self, data):
def show(self, data, *include_keys):
'''Pretty print a dict or list of dicts.'''

if isinstance(data, Mapping):
if include_keys:
data = {k: data[k] for k in include_keys if k in data}
print(yaml_dump(dict(data)).decode('utf-8'))
return
elif isinstance(data, basestring):
Expand All @@ -407,8 +514,8 @@ def show(self, data):

try:
for obj in data:
self.show(obj, *include_keys)
print('')
print(yaml_dump(obj).decode('utf-8'))
except:
print('Can not format: %s' % data)

Expand Down
16 changes: 13 additions & 3 deletions construct/compat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# -*- coding: utf-8 -*-
'''
Python2-3 Compatability
-----------------------
Rather than performing variable imports on a module by module basis, all
python compatability issues are handled here. This makes imports throughout
construct slightly neater than otherwise.
'''

# Third party imports
import six

Expand All @@ -9,9 +17,9 @@
from pathlib import Path

try:
from collections.abc import Mapping
from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence
except ImportError:
from collections import Mapping
from collections import Mapping, MutableMapping, MutableSequence, Sequence

if six.PY2:
import functools
Expand All @@ -22,9 +30,11 @@ def wraps(wrapped, assigned=_assignments, updated=_updates):
assigned = set(members) & set(assigned)
updated = set(members) & set(updated)
return functools.wraps(wrapped, assigned, updated)

from itertools import izip_longest as zip_longest
else:
from functools import wraps

from itertools import zip_longest

# Instead of python-future
basestring = six.string_types
Expand Down
2 changes: 1 addition & 1 deletion construct/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
}
}
DEFAULT_TREE = {
'asset': '{mount}/{project}/{bin}/{asset_type}/{asset}',
'asset': '{mount}/{project}/{bin}/{asset}',
'workspace': '{mount}/{project}/{bin}/{asset}/work/{task}/{host}',
'publish': '{mount}/{project}/{bin}/{asset}/publish/{item}/v{version:0>3d}',
'review': '{mount}/{project}/{bin}/{asset}/review/{task}/{host}',
Expand Down
Loading