Skip to content
This repository was archived by the owner on Oct 10, 2024. It is now read-only.

Commit d741d5d

Browse files
committed
Merge branch 'release/2.4-pype'
2 parents 181c7ec + 7df5d46 commit d741d5d

File tree

24 files changed

+559
-352
lines changed

24 files changed

+559
-352
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
**What happened?**
11+
A clear and concise description of what the bug is, e.g. *"when I clicked on X, Y happened"*
12+
13+
**What did you expect?**
14+
A similarly short description of your expectations, e.g. *"Z should have happened"*.
15+
16+
**To Reproduce**
17+
Steps to reproduce the behavior, preferably a bullet-list.
18+
19+
**Additional context**
20+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is, e.g. *"To many clicks to do X"*
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen, e.g. *"Wish I could multi-select"*
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

.github/pull_request_template.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Thank you for your contribution to Avalon! Here's how you can get your code merged quickly.
2+
3+
**What's changed?**
4+
Briefly summarise the changes you've made, something human-readable to get the reader up-to-speed with your thought process (hint: everyone loves bullet-lists). If the PR is in response to an existing issue (it should), link to this here.
5+
6+
**Health Check**
7+
To ensure your code lives up the standards of Avalon, consult the [Pull-Request](https://github.com/getavalon/core/blob/master/CONTRIBUTING.md#pull-request) section of `CONTRIBUTION.md` for details.
8+
9+
**Examples**
10+
If you are unsure of how to format your pull-request, have a look at these examples. [#403](https://github.com/getavalon/core/pull/403), [#400](https://github.com/getavalon/core/pull/400)

CONTRIBUTING.md

Lines changed: 210 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,215 @@
1-
### Contributing
1+
### Contribution Guidelines
22

3-
Hi and welcome to the Avalon pipeline project!
3+
Thanks for considering making a contribution to Avalon!
4+
5+
![image](https://user-images.githubusercontent.com/2152766/63447058-3dc1d480-c433-11e9-8f7d-215a956192a6.png)
6+
7+
Here are some guidelines for how you can help.
8+
9+
**Table of Contents**
10+
11+
- [Making Feature Requests](#feature-request)
12+
- [Reporting a Bug](#bug)
13+
- [Submitting a Pull-Request](#pull-request)
14+
- [Rules](#rules)
15+
- [Description](#description)
16+
- [Etiquette](#code-quality--etiquette)
17+
- [Complexity](#code-quality--complexity)
18+
- [Architecture](#code-quality--architecture)
19+
- [API](#api)
20+
21+
<br>
22+
23+
<img align=right src=https://user-images.githubusercontent.com/2152766/63447163-6f3aa000-c433-11e9-90a1-febdeadc9d8e.png>
24+
25+
### Feature Request
26+
27+
If you have an idea for a new or missing feature, you can submit a GitHub issue with the following ingredients.
28+
29+
| # | | Description
30+
|--|:---------|:-
31+
| 1 | **Goal** | In one sentence, what is the purpose of the feature?
32+
| 2 | **Motivation** | Why does it need to exist? What made you think of it? Feel free to elaborate, the more we understand the more able we will be to figure out the best solution, or point towards an existing (but not so visible) solution.
33+
| 3 | **Implementation** | Optional. Got an idea of how to implement it, but would like to talk about it first? This is a great place to do just that.
34+
35+
**But First**
36+
37+
1. [Search](https://github.com/getavalon/core/issues) for whether the feature you seek has already been requested and/or implemented
38+
1. [Ask](https://gitter.im/getavalon/Lobby) whether what you seek to do can be done.
39+
40+
**Examples**
41+
42+
- [#385](https://github.com/getavalon/core/issues/385)
43+
- [#390](https://github.com/getavalon/core/issues/390)
44+
- [#415](https://github.com/getavalon/core/issues/415)
445

546
<br>
647

7-
### Labels
48+
<img align=right src=https://user-images.githubusercontent.com/2152766/63447114-592cdf80-c433-11e9-9216-905361ef5495.png>
49+
50+
### Bug
51+
52+
When you run into bugs, you can submit an issue. In order for it to be resolved quickly, a bug report should contain:
53+
54+
| # | | Description
55+
|--|:---------|:-
56+
| 1 | **Problem** | What happened? Keep it short
57+
| 2 | **Reproducible** | How can someone else encounter the bug? Keep it minimal
58+
| 3 | **Attempts** | What have you tried so far?
59+
| 4 | **Solution** | Optional. If you've got an idea of what to do about it, but would like to talk about it before diving into code, here's your chance
60+
61+
It's hard to make an exact checklist out of these, as it depends on the particular bug.
62+
63+
**Examples**
64+
65+
- [#389](https://github.com/getavalon/core/issues/389)
66+
- [#377](https://github.com/getavalon/core/issues/377)
67+
- [#412](https://github.com/getavalon/core/issues/412)
68+
69+
<br>
70+
71+
<img align=right src=https://user-images.githubusercontent.com/2152766/63447191-824d7000-c433-11e9-853d-cdc19ef5cd1b.png>
72+
73+
### Pull Request
74+
75+
Here's what to keep in mind as you contribute code to Avalon. The overall goal is getting code merged as quickly as possible. Ambiguity cause delays, treat written English as code; it should be clear and concise.
76+
77+
> <img width=60 align=left src=https://user-images.githubusercontent.com/2152766/63446193-aad46a80-c431-11e9-8141-73597bda233a.png> Unlike issues, PRs fall under much stricter scrutiny. But don't let the amount of guidelines discourage you. You are not meant to know these by heart anymore than you are your local laws. Like laws however they will be referred back to during review and should hold up in anything actually merged into the codebase. So do glance over them, but remember to have fun!
78+
79+
##### Rules
80+
81+
1. Every new line of code needs purpose and motivation, preferably in the shape of an issue, alternatively as a linked topic in chat. The goal is giving future developers (ourselves included) an understanding of why something was done the way that it was.
82+
1. Every removed line of code needs a reason; but if you do manage to remove code without breaking things, you're a star and most welcome to contribute.
83+
84+
##### Description
85+
86+
When you present your PR, here's what you need to do.
87+
88+
1. Briefly summarise the changes, everybody loves bullet lists
89+
1. Refer to a related issue, if one exists. Else, make one, and refer to [Feature Request](#feature-request) above.
90+
2. Adhere to code quality standards, see below.
91+
92+
<br>
93+
94+
##### Code Quality - Etiquette
95+
96+
Here are a few things to keep in mind with regards to code etiquette.
97+
98+
| # | | Description | Example
99+
|---|:---------|:------------|---
100+
| E1 | PEP8 | All code must be PEP8 compatible, that means snake_case, spaces not tabs [and more](https://www.python.org/dev/peps/pep-0008/)
101+
| E2 | flake8 | All code must pass [flake8](http://flake8.pycqa.org/en/latest/). Recommend you use a linter for your text editor, such as `SublimeLinter-flake8`
102+
| E3 | Optimise for reading | Not writing. Code is read 10+ times more often than it is written.
103+
| E4 | Use UK English | Neither is correct, one is better than two | [Example](#e3)
104+
105+
<br>
106+
107+
##### Code Quality - Complexity
108+
109+
| # | | Description
110+
|--|:---------|:-
111+
| C1 | Loose coupling | Prefer code with few dependencies. Try and make functions run even if every other function around it failed.
112+
| C2 | Code reuse | Sharing code is great, just keep in mind that the ugly twin of code reuse is tight coupling. For example, sharing a widget between two windows creates a tight coupling between the two windows. If one breaks, so does the other. Sometimes reuse is appropriate, other times duplication is.
113+
| C3 | Testable code | Avoid implicit dependencies from within function, especially to calls into the OS or database. For example, a function that takes a `representation` dictionary and returns a path could operate entirely with only the data provided. Once it requires access to disk or database, it becomes that much harder to test, and therefore fragile
114+
| C4 | Prefer doctests | To unit- and integration-tests. If functionality can be tested directly from within its own docstring, the better. The result is self-contained functions whereby tests also double-serve as examples for the user.
115+
| C5 | Proactive and Reactive | APIs are *proactive*, GUIs are *reactive*. E.g. `api.do_something()` and `gui.on_something_done()`. GUIs do nothing but respond to user input and methods should be named accordingly. APIs on the other hand cannot respond to anything, they perform an action and return a result.
116+
117+
<br>
118+
119+
##### Code Quality - Architecture
120+
121+
Less obvious, but equally important guidelines for high-level code quality.
122+
123+
| # | | Description
124+
|--|:---------|:-
125+
| A1 | Minimal indirection | In order to cope with the cognitive overhead of traversing code, keep relevant code together.
126+
| A2 | Only separate what is shared | If a function is only ever used by one module, it should become part of that module. Likewise for modules used by a package.
127+
| A3 | Prefer fewer large modules to many small | Whenever you import a module, you create a dependency. The less of those there are, the better. That means no modules with just a single class.
128+
| A4 | Upward and lateral imports | A module may reach up and sideways in the package hierarchy, but not down. E.g. `avalon/maya/lib.py` may reach `avalon/io.py`, but `io.py` may not reach into `maya`.
129+
| A5 | Shallow dependency tree | Avoid traversing more than 3 levels anywhere, unless there is good reason. 3 is plenty.
130+
| A6 | Group by dependency, not type | That is, if 6 modules share code, they should share a package. If 12 functions are used by a single module, they should be part of that module.
131+
| A7 | Namespaces are good | Do not duplicate namespaces, e.g. `avalon.gui.models.model_subset` where "model" appears twice.
132+
| A8 | Namespaces are good | Do not import functions or classes, import modules and keep their namespace. E.g. `QtWidgets.QPushButton` is better than `QPushButton`.
133+
| A9 | Namespaces are good | Do not consolidate multiple modules into one, with the exception of `api.py`. Doing so makes it difficult to understand where things come from and where to look for them. `api.py` is different because it is the API; users are not supposed to know where code resides internally as that is implementation detail.
134+
135+
**Examples**
136+
137+
- **Bad**: https://github.com/getavalon/core/pull/414, vague, subjective
138+
- **Good**: https://github.com/getavalon/core/pull/400, minimal, clear goal
139+
- **Bad**: https://github.com/getavalon/core/pull/413, no motivation, no goal
140+
- **Good**: https://github.com/getavalon/core/pull/403, minimal, clear goal
141+
142+
<br>
143+
144+
<img align=right src=https://user-images.githubusercontent.com/2152766/63447271-a4df8900-c433-11e9-811f-372270f00e9f.png>
145+
146+
### API
147+
148+
Avalon is a framework, akin to PyQt, flask or OpenGL. Code is exposed to clients via `avalon.api` and supported integrations, such as `avalon.maya`. Access to any other module, including `avalon.io`, `avalon.maya.lib` and `avalon.tools.*` are *discouraged* as they are implementation details to these public APIs. Use at your own risk.
149+
150+
As a user of Avalon, if there is something you find in any contained submodule that *isn't* exposed via the API, here's what you do.
151+
152+
1. [Ask for it](https://gitter.im/getavalon/Lobby) to be exposed, odds are there is already something in there to achieve the goal you seek
153+
2. [Submit an issue](#feature-request), clarifying what and why you want something exposed, taking into consideration the below rules.
154+
155+
**Rules**
156+
157+
- APIs are for *client* use, and should not be used internally. Use internally results in cyclic dependencies and tight coupling between every module exposed by API to any internal module referencing it.
158+
- `api.py` and host-APIs are *additive*, meaning nothing is ever removed.
159+
- Members `api.py` and host-APIs are guaranteed to remain stable and unchanged *forever*, with two exceptions.
160+
1. Avalon is incremented from X.0 to Y.0, as per [semantic versioning](https://semver.org)
161+
2. Extenuating circumstances compels a breaking change to be made, for example someone's life is at stake
162+
163+
With this in mind, exposed members should be kept to a minimal and be appropriately general. Remember, once something is added to an API, there is no going back. Clients can expect members of an API to work forever and not break their code.
164+
165+
Because Avalon and Avalon's API is both written in Python, it can sometimes be difficult to separate between what is an API, and what is internal, but think of it this way; you couldn't import the C++ files that make Qt, or DLLs that make OpenGL. Only the interface is accessible to you, that's what enables these frameworks to evolve and improve, without breaking code that depend on it.
166+
167+
**Examples**
168+
169+
| Bad | Good
170+
|:-----|:--------
171+
| `api.asset_or_shot_data(document)` | `api.data()`
172+
| `api.open_file_from_last_week()` | `api.open_file(fname)`
173+
| `api.install_with_delay()` | `api.install()`
174+
| `api.log_welcome_message()` | `api.log_message("welcome")`
175+
176+
<br>
177+
178+
### Examples
179+
180+
##### E3
181+
182+
Optimise for reading, which means preserve import namespaces, do not shorten arguments or variables.
183+
184+
<table>
185+
<tr>
186+
</tr>
187+
<tr>
188+
<td>Bad</th>
189+
<td>
190+
191+
```py
192+
from long_module_name import LongClassName as L
193+
...
194+
bs = [L(n="Button%s" % i) for i in range(3)]
195+
```
196+
197+
</td>
198+
<tr>
199+
</tr>
200+
</tr>
201+
<tr>
202+
<td>Good</td>
203+
<td>
204+
205+
```py
206+
import long_module_name
207+
...
208+
button1 = long_module_name.LongClassName(name="Button1")
209+
button2 = long_module_name.LongClassName(name="Button2")
210+
button3 = long_module_name.LongClassName(name="Button3")
211+
```
8212

9-
| Label | Description
10-
|:---------|:----------------
11-
| `epic` | A big chunk of work with one common objective, needed to be separated into individual, smaller issues.
213+
</td>
214+
</tr>
215+
</table>

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ $ . test_docker.sh
2727

2828
<br>
2929

30+
### Contributing
31+
32+
See [CONTRIBUTING.md](https://github.com/getavalon/core/blob/master/CONTRIBUTING.md) for a summary of guidelines for how you can contribute to Avalon.
33+
34+
Also visit [the chat](https://gitter.im/getavalon/Lobby) for a direct connection with current developers.
35+
36+
<br>
37+
3038
### Code convention
3139

3240
Below are some of the standard practices applied to this repositories.

avalon/__main__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import os
12
import argparse
23

3-
from . import pipeline, version
4+
from . import pipeline, version, api
45

56

67
def main():
@@ -17,6 +18,8 @@ def main():
1718
help="Launch Scene Inventory in standalone mode")
1819
parser.add_argument("--projectmanager", action="store_true",
1920
help="Launch Manager in standalone mode")
21+
parser.add_argument("--workfiles", action="store_true",
22+
help="Launch Workfiles in standalone mode")
2023

2124
args, unknown = parser.parse_known_args()
2225
host = pipeline.debug_host()
@@ -28,10 +31,12 @@ def main():
2831

2932
elif args.creator:
3033
from .tools import creator
34+
api.Session["AVALON_ASSET"] = "Mock"
3135
creator.show(debug=True)
3236

3337
elif args.loader:
3438
from .tools import loader
39+
api.Session["AVALON_PROJECTS"] = os.path.expanduser("~/projects")
3540
loader.show(debug=True)
3641

3742
elif args.sceneinventory:
@@ -42,6 +47,10 @@ def main():
4247
from .tools import projectmanager
4348
projectmanager.cli(unknown)
4449

50+
elif args.workfiles:
51+
from .tools import workfiles
52+
workfiles.show(debug=True)
53+
4554
else:
4655
parser.print_help()
4756

avalon/houdini/pipeline.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ def find_host_config(config):
7575
return config
7676

7777

78+
def get_main_window():
79+
"""Acquire Houdini's main window"""
80+
if self._parent is None:
81+
self._parent = hou.ui.mainQtWindow()
82+
return self._parent
83+
84+
7885
def reload_pipeline(*args):
7986
"""Attempt to reload pipeline at run-time.
8087
@@ -116,7 +123,7 @@ def reload_pipeline(*args):
116123
module = importlib.import_module(module)
117124
reload(module)
118125

119-
self._parent = {hou.ui.mainQtWindow().objectName(): hou.ui.mainQtWindow()}
126+
get_main_window()
120127

121128
import avalon.houdini
122129
api.install(avalon.houdini)
@@ -201,12 +208,11 @@ def containerise(name,
201208
return container
202209

203210

204-
def parse_container(container, validate=True):
211+
def parse_container(container):
205212
"""Return the container node's full container data.
206213
207214
Args:
208215
container (hou.Node): A container node name.
209-
validate(bool): turn the validation for the container on or off
210216
211217
Returns:
212218
dict: The container schema data for this container node.
@@ -221,9 +227,6 @@ def parse_container(container, validate=True):
221227
data["objectName"] = container.path()
222228
data["node"] = container
223229

224-
if validate:
225-
schema.validate(data)
226-
227230
return data
228231

229232

@@ -321,9 +324,7 @@ def on_file_event_callback(event):
321324

322325

323326
def on_houdini_initialize():
324-
325-
main_window = hou.qt.mainWindow()
326-
self._parent = {main_window.objectName(): main_window}
327+
get_main_window()
327328

328329

329330
def _register_callbacks():

0 commit comments

Comments
 (0)