maya-umbrella 0.8.0__py2.py3-none-any.whl → 0.10.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of maya-umbrella might be problematic. Click here for more details.

maya_umbrella/__init__.py CHANGED
@@ -3,7 +3,16 @@ from maya_umbrella.cleaner import MayaVirusCleaner
3
3
  from maya_umbrella.collector import MayaVirusCollector
4
4
  from maya_umbrella.defender import MayaVirusDefender
5
5
  from maya_umbrella.defender import context_defender
6
+ from maya_umbrella.defender import get_defender_instance
6
7
  from maya_umbrella.scanner import MayaVirusScanner
7
8
 
8
9
 
9
- __all__ = ["MayaVirusDefender", "MayaVirusCleaner", "MayaVirusCollector", "MayaVirusScanner", "context_defender"]
10
+ # All public APIs.
11
+ __all__ = [
12
+ "MayaVirusDefender",
13
+ "MayaVirusCleaner",
14
+ "MayaVirusCollector",
15
+ "MayaVirusScanner",
16
+ "context_defender",
17
+ "get_defender_instance",
18
+ ]
@@ -1 +1 @@
1
- __version__ = "0.8.0"
1
+ __version__ = "0.10.0"
maya_umbrella/defender.py CHANGED
@@ -15,6 +15,7 @@ from maya_umbrella.maya_funs import om
15
15
 
16
16
  # Global list to store IDs of Maya callbacks
17
17
  MAYA_UMBRELLA_CALLBACK_IDS = []
18
+ MAYA_UMBRELLA_DEFENDER = None
18
19
 
19
20
 
20
21
  def _add_callbacks_id(id_):
@@ -115,10 +116,11 @@ class MayaVirusDefender(object):
115
116
 
116
117
  def stop(self):
117
118
  """Stop the MayaVirusDefender."""
118
- for ids in MAYA_UMBRELLA_CALLBACK_IDS:
119
- self.logger.debug("remove callback. %s", ids)
120
- om.MSceneMessage.removeCallback(ids)
121
- MAYA_UMBRELLA_CALLBACK_IDS.remove(ids)
119
+ while MAYA_UMBRELLA_CALLBACK_IDS:
120
+ for ids in MAYA_UMBRELLA_CALLBACK_IDS:
121
+ self.logger.debug("remove callback. %s", ids)
122
+ om.MSceneMessage.removeCallback(ids)
123
+ MAYA_UMBRELLA_CALLBACK_IDS.remove(ids)
122
124
 
123
125
  def get_unfixed_references(self):
124
126
  """Get the list of unfixed reference files.
@@ -155,7 +157,19 @@ def context_defender():
155
157
  Yields:
156
158
  MayaVirusDefender: An instance of MayaVirusDefender.
157
159
  """
158
- defender = MayaVirusDefender()
160
+ defender = get_defender_instance()
159
161
  defender.stop()
160
162
  yield defender
161
163
  defender.setup()
164
+
165
+
166
+ def get_defender_instance():
167
+ """Get the MayaVirusDefender instance.
168
+
169
+ Returns:
170
+ MayaVirusDefender: The MayaVirusDefender instance.
171
+ """
172
+ global MAYA_UMBRELLA_DEFENDER
173
+ if MAYA_UMBRELLA_DEFENDER is None:
174
+ MAYA_UMBRELLA_DEFENDER = MayaVirusDefender()
175
+ return MAYA_UMBRELLA_DEFENDER
@@ -1,8 +1,10 @@
1
1
  # Import built-in modules
2
+ import codecs
2
3
  from contextlib import contextmanager
3
4
  import glob
4
5
  import importlib
5
6
  import json
7
+ import logging
6
8
  import os
7
9
  import random
8
10
  import re
@@ -41,6 +43,22 @@ def safe_rmtree(path):
41
43
  pass
42
44
 
43
45
 
46
+ def _codes_open(path, encoding="utf-8"):
47
+ """Open and read the content of a file using the specified encoding.
48
+
49
+ Args:
50
+ path (str): Path to the file.
51
+ encoding (str, optional): The encoding to use when reading the file. Defaults to "utf-8".
52
+
53
+ Returns:
54
+ str: The content of the file, or an empty string if the file could not be read.
55
+ """
56
+ try:
57
+ with codecs.open(path, "r", encoding) as file_:
58
+ return file_.read()
59
+ except (OSError, IOError): # noqa: UP024
60
+ return ""
61
+
44
62
  def read_file(path):
45
63
  """Read the content of the file at the given path."""
46
64
  options = {"encoding": "utf-8"} if PY3 else {}
@@ -89,7 +107,8 @@ def atomic_writes(src, mode, **options):
89
107
  AttributeError: If the os module does not have the 'replace' function (Python 2 compatibility).
90
108
  """
91
109
  temp_path = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
92
- with open(temp_path, mode, **options) as f:
110
+ open_func = open if PY3 else codecs.open
111
+ with open_func(temp_path, mode, **options) as f:
93
112
  yield f
94
113
  try:
95
114
  os.replace(temp_path, src)
@@ -97,7 +116,6 @@ def atomic_writes(src, mode, **options):
97
116
  shutil.move(temp_path, src)
98
117
 
99
118
 
100
-
101
119
  def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
102
120
  """Generate a random string of the given size using the given characters."""
103
121
  return "".join(random.choice(chars) for _ in range(size))
@@ -174,7 +192,7 @@ def get_log_file():
174
192
  return os.path.join(root, "{name}.log".format(name=name))
175
193
 
176
194
 
177
- def remove_virus_file_by_signature(file_path, signatures, output_file_path=None):
195
+ def remove_virus_file_by_signature(file_path, signatures, output_file_path=None, auto_remove=True):
178
196
  """Remove virus content from a file by matching signatures.
179
197
 
180
198
  Args:
@@ -182,11 +200,23 @@ def remove_virus_file_by_signature(file_path, signatures, output_file_path=None)
182
200
  signatures (list): List of signatures to match and remove.
183
201
  output_file_path (str, optional): Path to the cleaned output file.
184
202
  Defaults to None, which overwrites the input file.
203
+ auto_remove: If True, remove the input file if the output file is empty.
204
+
185
205
  """
186
- data = read_file(file_path)
206
+ try:
207
+ data = read_file(file_path)
208
+ except (OSError, IOError): # noqa: UP024
209
+ return False
210
+ except UnicodeDecodeError:
211
+ data = _codes_open(file_path)
187
212
  if check_virus_by_signature(data, signatures):
188
- fixed_data = replace_content_by_signatures(data, signatures)
189
- write_file(output_file_path or file_path, fixed_data)
213
+ fixed_data = replace_content_by_signatures(data, signatures).strip()
214
+ if fixed_data:
215
+ write_file(output_file_path or file_path, fixed_data)
216
+ else:
217
+ # Auto remove empty files.
218
+ if auto_remove:
219
+ os.remove(file_path)
190
220
 
191
221
 
192
222
  def replace_content_by_signatures(content, signatures):
@@ -217,11 +247,11 @@ def check_virus_file_by_signature(file_path, signatures=None):
217
247
  signatures = signatures or FILE_VIRUS_SIGNATURES
218
248
  try:
219
249
  data = read_file(file_path)
220
- return check_virus_by_signature(data, signatures)
221
250
  except (OSError, IOError): # noqa: UP024
222
251
  return False
223
252
  except UnicodeDecodeError:
224
- return True
253
+ data = _codes_open(file_path)
254
+ return check_virus_by_signature(data, signatures)
225
255
 
226
256
 
227
257
  def check_virus_by_signature(content, signatures=None):
@@ -266,3 +296,32 @@ def get_backup_path(path, root_path=None):
266
296
  except (OSError, IOError): # noqa: UP024
267
297
  pass
268
298
  return os.path.join(backup_path, filename)
299
+
300
+
301
+ def get_maya_install_root(maya_version):
302
+ """Get the Maya install root path."""
303
+ logger = logging.getLogger(__name__)
304
+ maya_location = os.getenv("MAYA_LOCATION")
305
+ try:
306
+ # Import built-in modules
307
+ import winreg
308
+ except ImportError:
309
+ return maya_location
310
+ try:
311
+ key = winreg.OpenKey(
312
+ winreg.HKEY_LOCAL_MACHINE,
313
+ "SOFTWARE\\Autodesk\\Maya\\{maya_version}\\Setup\\InstallPath".format(maya_version=maya_version),
314
+ )
315
+ root, _ = winreg.QueryValueEx(key, "MAYA_INSTALL_LOCATION")
316
+ if not os.path.isdir(root):
317
+ logger.info("Failed to locate the appropriate Maya path in the registration list.")
318
+ except OSError:
319
+ return maya_location
320
+ maya_location = maya_location or root
321
+ if not maya_location:
322
+ logger.info("maya not found.")
323
+ return
324
+ maya_exe = os.path.join(maya_location, "bin", "maya.exe")
325
+ if not os.path.exists(maya_exe):
326
+ logger.info("maya.exe not found in {maya_location}.".format(maya_location=maya_location))
327
+ return maya_location
@@ -6,26 +6,26 @@ def hook(virus_cleaner):
6
6
  unknown_node = cmds.ls(type="unknown")
7
7
  unknown_plugin = cmds.unknownPlugin(query=True, l=True)
8
8
  if unknown_node:
9
- for nodeObj in unknown_node:
10
- if cmds.objExists(nodeObj):
11
- if cmds.referenceQuery(nodeObj, isNodeReferenced=True):
12
- virus_cleaner.logger.warning("Node from reference, skip. {}".format(nodeObj))
9
+ for node_obj in unknown_node:
10
+ if cmds.objExists(node_obj):
11
+ if cmds.referenceQuery(node_obj, isNodeReferenced=True):
12
+ virus_cleaner.logger.warning("Node from reference, skip. {}".format(node_obj))
13
13
  continue
14
- if cmds.lockNode(nodeObj, query=True)[0]:
14
+ if cmds.lockNode(node_obj, query=True)[0]:
15
15
  try:
16
- cmds.lockNode(nodeObj, lock=False)
16
+ cmds.lockNode(node_obj, lock=False)
17
17
  except Exception:
18
18
  virus_cleaner.logger.warning(
19
- "The node is locked and cannot be unlocked. skip {}".format(nodeObj)
19
+ "The node is locked and cannot be unlocked. skip {}".format(node_obj)
20
20
  )
21
21
  continue
22
22
  try:
23
- cmds.delete(nodeObj)
24
- virus_cleaner.logger.warning("Delete node: {}".format(nodeObj))
23
+ cmds.delete(node_obj)
24
+ virus_cleaner.logger.warning("Delete node: {}".format(node_obj))
25
25
  except Exception:
26
26
  pass
27
27
 
28
28
  if unknown_plugin:
29
- for plugObj in unknown_plugin:
30
- cmds.unknownPlugin(plugObj, remove=True)
31
- virus_cleaner.logger.warning("Delete plug-in: {}".format(plugObj))
29
+ for plug_obj in unknown_plugin:
30
+ cmds.unknownPlugin(plug_obj, remove=True)
31
+ virus_cleaner.logger.warning("Delete plug-in: {}".format(plug_obj))
maya_umbrella/i18n.py CHANGED
@@ -16,6 +16,7 @@ class Translator(object):
16
16
  data (dict): Dictionary containing translation data for different locales.
17
17
  locale (str): The current locale.
18
18
  """
19
+
19
20
  def __init__(self, file_format="json", default_locale=None):
20
21
  """Initialize the Translator.
21
22
 
@@ -24,8 +25,7 @@ class Translator(object):
24
25
  default_locale (str, optional): Default locale to use for translations. Defaults to None,
25
26
  which uses the MAYA_UMBRELLA_LANG environment variable or the Maya UI language.
26
27
  """
27
- _default_locale = os.getenv("MAYA_UMBRELLA_LANG", maya_ui_language())
28
- default_locale = default_locale or _default_locale
28
+ default_locale = default_locale or os.getenv("MAYA_UMBRELLA_LANG", maya_ui_language())
29
29
  self.data = {}
30
30
  self.locale = default_locale
31
31
  translations_folder = os.path.join(this_root(), "locales")
maya_umbrella/log.py CHANGED
@@ -1,5 +1,7 @@
1
1
  # Import built-in modules
2
- import logging.handlers
2
+ from logging import Formatter
3
+ from logging import getLogger
4
+ from logging import handlers
3
5
  import os
4
6
 
5
7
  # Import local modules
@@ -20,18 +22,18 @@ def setup_logger(logger=None, logfile=None, log_level=None):
20
22
  Returns:
21
23
  logging.Logger: The set up logger.
22
24
  """
23
- logger = logger or logging.getLogger(PACKAGE_NAME)
25
+ logger = logger or getLogger(PACKAGE_NAME)
24
26
  log_level = log_level or os.getenv("MAYA_UMBRELLA_LOG_LEVEL", "INFO")
25
27
  logger.setLevel(log_level)
26
28
  logfile = logfile or get_log_file()
27
29
  if not len(logger.handlers):
28
- filehandler = logging.handlers.RotatingFileHandler(
30
+ filehandler = handlers.RotatingFileHandler(
29
31
  logfile,
30
32
  mode="a",
31
33
  backupCount=7,
32
34
  delay=True,
33
35
  maxBytes=LOG_MAX_BYTES,
34
36
  )
35
- filehandler.setFormatter(logging.Formatter(LOG_FORMAT))
37
+ filehandler.setFormatter(Formatter(LOG_FORMAT))
36
38
  logger.addHandler(filehandler)
37
39
  return logger
@@ -137,7 +137,7 @@ def save_as_file(file_name):
137
137
  file_name (str): Path to the output file.
138
138
  """
139
139
  cmds.file(rename=file_name)
140
- cmds.file(s=True, f=True)
140
+ cmds.file(save=True, force=True)
141
141
 
142
142
 
143
143
  @contextmanager
maya_umbrella/scanner.py CHANGED
@@ -30,7 +30,7 @@ class MayaVirusScanner(object):
30
30
 
31
31
  Args:
32
32
  output_path (str, optional): Path to save the fixed files. Defaults to None, which overwrites the original
33
- files.
33
+ files.
34
34
  env (dict, optional): Custom environment variables. Defaults to None,
35
35
  which sets the 'MAYA_COLOR_MANAGEMENT_SYNCOLOR' variable to '1'.
36
36
  """
@@ -99,7 +99,7 @@ class MayaVirusScanner(object):
99
99
  backup_path = get_backup_path(maya_file, root_path=self.output_path)
100
100
  self.logger.debug("Backup saved to: {backup_path}".format(backup_path=backup_path))
101
101
  shutil.copy2(maya_file, backup_path)
102
- cmds.file(s=True, f=True)
102
+ cmds.file(save=True, force=True)
103
103
  self._fixed_files.append(maya_file)
104
104
  self._reference_files.extend(self.defender.collector.infected_reference_files)
105
105
  cmds.file(new=True, force=True)
@@ -1,5 +1,5 @@
1
1
  # Import built-in modules
2
- import os.path
2
+ import os
3
3
 
4
4
  # Import local modules
5
5
  from maya_umbrella.constants import JOB_SCRIPTS_VIRUS_SIGNATURES
@@ -42,10 +42,12 @@ class Vaccine(AbstractVaccine):
42
42
 
43
43
  def collect_infected_user_setup_py(self):
44
44
  """Collect all bad userSetup.py files related to the virus."""
45
- for user_setup_py in [
45
+ user_setup_py_files = [
46
46
  os.path.join(self.api.local_script_path, "userSetup.py"),
47
47
  os.path.join(self.api.user_script_path, "userSetup.py"),
48
- ]:
48
+ ]
49
+
50
+ for user_setup_py in user_setup_py_files:
49
51
  if os.path.exists(user_setup_py):
50
52
  if check_virus_file_by_signature(user_setup_py):
51
53
  self.report_issue(user_setup_py)
@@ -18,37 +18,47 @@ class Vaccine(AbstractVaccine):
18
18
 
19
19
  virus_name = "Virus2024429"
20
20
 
21
+ @staticmethod
22
+ def is_infected(script_node):
23
+ """Check if a script node is infected with a virus.
24
+
25
+ Args:
26
+ script_node (str): The name of the script node to check.
27
+
28
+ Returns:
29
+ bool: True if the script node is infected, False otherwise.
30
+ """
31
+ if "_gene" in script_node:
32
+ return True
33
+ if "uifiguration" in script_node:
34
+ for attr_name in ("before", "notes"):
35
+ script_string = get_attr_value(script_node, attr_name)
36
+ if script_string and check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
37
+ return True
38
+ return False
39
+
21
40
  def collect_infected_nodes(self):
22
41
  """Collect all bad nodes related to the virus."""
23
42
  for script_node in cmds.ls(type="script"):
24
- # check vaccine
25
- if "_gene" in script_node:
43
+ if self.is_infected(script_node):
26
44
  self.report_issue(script_node)
27
45
  self.api.add_infected_node(script_node)
28
46
  self.api.add_infected_reference_file(get_reference_file_by_node(script_node))
29
- if "uifiguration" in script_node:
30
- for attr_name in ("before", "notes"):
31
- script_string = get_attr_value(script_node, attr_name)
32
- if not script_string:
33
- continue
34
- if check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
35
- self.report_issue(script_node)
36
- self.api.add_infected_node(script_node)
37
- self.api.add_infected_reference_file(get_reference_file_by_node(script_node))
38
47
 
39
48
  def collect_infected_mel_files(self):
40
49
  """Collect all bad MEL files related to the virus."""
41
50
  # check usersetup.mel
42
51
  # C:/Users/hallong/Documents/maya/scripts/usersetup.mel
43
52
  # C:/Users/hallong/Documents/maya/xxxx/scripts/usersetup.mel
44
- for usersetup_mel in [
53
+ usersetup_mel_paths = [
45
54
  os.path.join(self.api.local_script_path, "usersetup.mel"),
46
55
  os.path.join(self.api.user_script_path, "usersetup.mel"),
47
- ]:
48
- if os.path.exists(usersetup_mel):
49
- if check_virus_file_by_signature(usersetup_mel):
50
- self.report_issue(usersetup_mel)
51
- self.api.add_infected_file(usersetup_mel)
56
+ ]
57
+
58
+ for usersetup_mel in usersetup_mel_paths:
59
+ if os.path.exists(usersetup_mel) and check_virus_file_by_signature(usersetup_mel):
60
+ self.report_issue(usersetup_mel)
61
+ self.api.add_infected_file(usersetup_mel)
52
62
 
53
63
  def collect_script_jobs(self):
54
64
  """Collect all script jobs related to the virus."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maya_umbrella
3
- Version: 0.8.0
3
+ Version: 0.10.0
4
4
  Summary: Check and fix maya virus.
5
5
  Home-page: https://github.com/loonghao/maya_umbrella
6
6
  License: MIT
@@ -53,10 +53,15 @@ It ensures a secure and seamless user experience by proactively scanning for thr
53
53
  It can be provided as an API for seamless integration into your existing pipeline.
54
54
 
55
55
  # 安装
56
+
57
+ ## pip 安装
56
58
  maya_umbrella是以标准pipy包去发布的,所以我们可以通过pip install去安装
57
59
  ```shell
58
60
  your/maya-root/mayapy -m pip install maya-umbrella
59
61
  ```
62
+ ## 一键安装
63
+ 在release里面下载对应版本的zip包,解压后双击`install.bat`即可安装
64
+
60
65
  更新版本
61
66
  ```shell
62
67
  your/maya-root/mayapy -m pip install maya-umbrella --upgrade
@@ -73,20 +78,25 @@ and it is recommended to use Python 3.8 or higher versions.
73
78
 
74
79
  通过虚拟环境去设置开发环境, 推荐python-3.8以上的版本
75
80
 
81
+ 通过pip安装相关开发依赖
82
+
76
83
  ```shell
77
- pip install nox poetry
84
+ pip install -r requirements-dev.txt
78
85
  ```
79
86
 
80
87
  # 开发调试
81
88
 
82
- ```shell
83
- nox -s maya-2020
84
- ```
85
89
 
86
90
  ## 在maya中测试
87
91
 
88
- 通过`nox -s maya-xxx`, 启动maya.
89
- nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,那么通过`nox -s maya-2018`
92
+ 通过`nox -s maya -- <maya version>`, 启动maya.
93
+ nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,
94
+ 那么通过可以启动带有测试环境的maya
95
+ ```shell
96
+ nox -s maya -- 2018
97
+ ```
98
+
99
+ **注意:maya 与 版本号之间有 俩个`-`**
90
100
 
91
101
  启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
92
102
 
@@ -96,6 +106,15 @@ import manual_test_in_maya
96
106
  manual_test_in_maya.start()
97
107
  ```
98
108
 
109
+ 也可以通过pytest去执行对应的测试,也需要本地安装了对应的maya
110
+
111
+ ```shell
112
+ nox -s maya -- 2018 --test
113
+ ```
114
+
115
+ **注意:在maya-2022 (PY2) 以下的版本可能会出现命令行crash的情况**
116
+
117
+
99
118
  ## 增加新的疫苗
100
119
 
101
120
  在`<repo>/maya_umbrella/vaccines/` 新建一个py, 因为有很多病毒没有具体的名字代号,我们统一以`vaccine<id>.py`
@@ -106,13 +125,20 @@ manual_test_in_maya.start()
106
125
  我们可以利用封装好的`nox`命令去执行进行代码检查
107
126
 
108
127
  ```shell
109
- nox -s ruff_check
128
+ nox -s lint
129
+ ```
130
+
131
+ 进行代码整理
132
+ ```shell
133
+ nox -s lint-fix
110
134
  ```
111
135
 
112
136
  # 生成安装包
113
137
 
114
138
  执行下面的命令可以在<repo>/.zip下面创建zip,参数 `--version` 当前工具的版本号
115
139
 
140
+ **注意:`make-zip` 与 `--version`之间有 俩个`-`**
141
+
116
142
  ```shell
117
143
  nox -s make-zip -- --version 0.5.0
118
144
  ```
@@ -155,14 +181,20 @@ MAYA_UMBRELLA_LANG
155
181
  MAYA_UMBRELLA_IGNORE_BACKUP
156
182
  ```
157
183
 
184
+ 如果忽略请设置为
185
+ ```shell
186
+ SET MAYA_UMBRELLA_IGNORE_BACKUP=true
187
+ ```
188
+
158
189
  如果是便携版Maya,可以通过添加 `MAYA_LOCATION` 环境变量指定Maya路径
159
190
  ```shell
160
191
  SET MAYA_LOCATION=d:/your/path/maya_version/
161
192
  ```
193
+ 也可以通过命令行指定目录
162
194
 
163
- 如果忽略请设置为
164
195
  ```shell
165
- SET MAYA_UMBRELLA_IGNORE_BACKUP=true
196
+ nox -s maya -- 2018 --install-root /your/local/maya/root
197
+
166
198
  ```
167
199
 
168
200
  # API
@@ -185,13 +217,16 @@ print(api.scan_files_from_pattern("your/path/*.m[ab]"))
185
217
  ```
186
218
 
187
219
  # 案例
188
- 如果你想要快速通过maya standalone去批量清理maya文件,可以`下载`或者`git clone`当前`main`分支的工程,
189
- 根据上面指引设置好开发环境
190
- 通过`nox`命令去启动maya standalone环境,maya版本根据你当前本地安装的maya为准,比如你本地安装了`2018`,
191
- 那么就是 `nox -s maya-2018-s`
220
+ 如果你想要快速通过maya standalone去批量清理maya文件,
221
+ 可以`下载`或者`git clone`当前`main`分支的工程,
222
+ 根据上面指引设置好开发环境,
223
+ 通过`nox`命令去启动maya `standalone`环境,maya版本根据你当前本地安装的maya为准,
224
+ 比如你本地安装了`2018`,
225
+ 那么就是 `nox -s maya -- 2018 --standalone`
192
226
  下面的语法是启动一个maya-2020的环境去动态从`c:/test`文件夹下去查杀病毒
227
+
193
228
  ```shell
194
- nox -s maya-2020-s -- c:/test/*.m[ab]
229
+ nox -s maya -- 2018 --standalone --pattern c:/test/*.m[ab]
195
230
  ```
196
231
 
197
232
  ## Contributors ✨
@@ -0,0 +1,28 @@
1
+ maya_umbrella/__init__.py,sha256=rcCnFWmELeJsGoKvLHyzC_GmZu-eT1QXjQCHRGj6HuQ,529
2
+ maya_umbrella/__version__.py,sha256=v4zmKjsKOPZbp6BrWoz7iK4ST0sdZdUh9bQSJmluZ5o,23
3
+ maya_umbrella/cleaner.py,sha256=5EC3w4qRkIsr9AIZneEV8ljhxaOw385Gj2C2KTrzyJg,5044
4
+ maya_umbrella/collector.py,sha256=rAFmvY8Isdle89ezn2-H36hSJd77iBvPBLRPzruCycA,13111
5
+ maya_umbrella/constants.py,sha256=2sl0dL0U82mwu-Msda9B8-USxr89Wu2yu6SYiuaaJZk,539
6
+ maya_umbrella/defender.py,sha256=eT4uK23uOB1V8Y3uiaU1C2Tp-s1SngrGo3TWDbSIVJY,6008
7
+ maya_umbrella/filesystem.py,sha256=AnKUDw6N1xU0YO4YaTiLzl88Ju7MYezetcyn87Te1iY,10442
8
+ maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ maya_umbrella/hooks/delete_turtle.py,sha256=OPFRFH1iwonHvETndrP87MZQlJLhxpe564AJE3KyJY8,761
10
+ maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=5YXaOem-t9Em1sr3wmBqWk5He1Lm8CsOMQsSQ3ixLfs,1293
11
+ maya_umbrella/hooks/fix_model_panel.py,sha256=dLuMOz5uQ1nqAboNWMCx-Bi_gHM3FQNTlGxPG5wRYEs,556
12
+ maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=o4WEQPcHNzaTMXdNnHZWWNCYlHfLxcSFYXR4YW0ZLwk,484
13
+ maya_umbrella/i18n.py,sha256=aWaIncHh5Zq02hErMbHHLoQm_8Fu-YfBWQ15sUgsBJk,2642
14
+ maya_umbrella/locales/en_US.json,sha256=LW2gPgO2YJIYR5UfcIBuxW_DS7rf4gkjeVuADqs1V5s,962
15
+ maya_umbrella/locales/zh_CN.json,sha256=UsuRN2yaxxc9LE-7NQkbMqrkjXjNhNegS0QRkQLSTiE,1006
16
+ maya_umbrella/log.py,sha256=8CY_sCPOmxDOY2oHLZel2QjZiY4HsXKwVu9vNWmScTc,1379
17
+ maya_umbrella/maya_funs.py,sha256=_4LaMO4cRTCcbgNj2ei7UtSLAnCRY_ylHiLGKgvM4sE,3652
18
+ maya_umbrella/scanner.py,sha256=pDU6RKez19kaaO_7HE4jG4h53XoloPCwiuVV8ajr2mo,3932
19
+ maya_umbrella/signatures.py,sha256=RkEXChch7tdqA9Yq6YQ8AMnK2ra6ih0dfnpeZy5FkYs,354
20
+ maya_umbrella/vaccine.py,sha256=aBW6pdT4tD4OMBPZ-d3E4_n16Rylz-2gb7JWzMZVPK0,1022
21
+ maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ maya_umbrella/vaccines/vaccine1.py,sha256=WLo1uJElTLSjVCf5CBtRNU4HKs63my5mkHiGqTfnNEE,489
23
+ maya_umbrella/vaccines/vaccine2.py,sha256=b2OmYjLCZRFIeeVr-EvQRrmYIGmTX4J9l9DtINAmo7E,2169
24
+ maya_umbrella/vaccines/vaccine3.py,sha256=LAP5QfDIlbiUM_A7O2Vnw4aFhDtojd2kAo2CFcHOKVE,3632
25
+ maya_umbrella-0.10.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
26
+ maya_umbrella-0.10.0.dist-info/METADATA,sha256=Tzf4ZBeqxgfvzer_rRMO1cZWgapHoeF0vFVgqonoZsI,11722
27
+ maya_umbrella-0.10.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
28
+ maya_umbrella-0.10.0.dist-info/RECORD,,
@@ -1,28 +0,0 @@
1
- maya_umbrella/__init__.py,sha256=uHgbJ-AL3NOfDNB55_7a4_c-OAuP4X8eQ_Yi1udaA0I,401
2
- maya_umbrella/__version__.py,sha256=iPlYCcIzuzW7T2HKDkmYlMkRI51dBLfNRxPPiWrfw9U,22
3
- maya_umbrella/cleaner.py,sha256=5EC3w4qRkIsr9AIZneEV8ljhxaOw385Gj2C2KTrzyJg,5044
4
- maya_umbrella/collector.py,sha256=rAFmvY8Isdle89ezn2-H36hSJd77iBvPBLRPzruCycA,13111
5
- maya_umbrella/constants.py,sha256=2sl0dL0U82mwu-Msda9B8-USxr89Wu2yu6SYiuaaJZk,539
6
- maya_umbrella/defender.py,sha256=K5EERl9bwd0IY_ilvnNYXYaQpIe-DUGep-buEb3qLV8,5601
7
- maya_umbrella/filesystem.py,sha256=CY3MlOXi_fJ8NTITvgotyPiZHyzM4uZQTgMmOYD25T0,8333
8
- maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- maya_umbrella/hooks/delete_turtle.py,sha256=OPFRFH1iwonHvETndrP87MZQlJLhxpe564AJE3KyJY8,761
10
- maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=xbJvihfjZBhF946ugVqj2IpY_VjOBZt_8KO5omDrJhw,1281
11
- maya_umbrella/hooks/fix_model_panel.py,sha256=dLuMOz5uQ1nqAboNWMCx-Bi_gHM3FQNTlGxPG5wRYEs,556
12
- maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=o4WEQPcHNzaTMXdNnHZWWNCYlHfLxcSFYXR4YW0ZLwk,484
13
- maya_umbrella/i18n.py,sha256=NCC6isPdchv3yRBS2F4Cguu1bVyi0VoMMcI4YOIxBtU,2683
14
- maya_umbrella/locales/en_US.json,sha256=LW2gPgO2YJIYR5UfcIBuxW_DS7rf4gkjeVuADqs1V5s,962
15
- maya_umbrella/locales/zh_CN.json,sha256=UsuRN2yaxxc9LE-7NQkbMqrkjXjNhNegS0QRkQLSTiE,1006
16
- maya_umbrella/log.py,sha256=IJweFEBTThL6_mW86jAAPKyWNvI79CrMifs5vO3t6ks,1338
17
- maya_umbrella/maya_funs.py,sha256=4Wty8e722V-stYofPGHGHKCIURP5Gp-qTOsodqXJ4MA,3645
18
- maya_umbrella/scanner.py,sha256=Souu4iFrYPJVV34actQf69Po6hHhGDv_7cRuKtGoygc,3921
19
- maya_umbrella/signatures.py,sha256=RkEXChch7tdqA9Yq6YQ8AMnK2ra6ih0dfnpeZy5FkYs,354
20
- maya_umbrella/vaccine.py,sha256=aBW6pdT4tD4OMBPZ-d3E4_n16Rylz-2gb7JWzMZVPK0,1022
21
- maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- maya_umbrella/vaccines/vaccine1.py,sha256=WLo1uJElTLSjVCf5CBtRNU4HKs63my5mkHiGqTfnNEE,489
23
- maya_umbrella/vaccines/vaccine2.py,sha256=yvHpnrQ6Jts9_zCy8WRJcbxz0CVSRAPkn2vF552atQs,2123
24
- maya_umbrella/vaccines/vaccine3.py,sha256=d89Ocj1AmsZt9YJjggjDJqAWXcckGLMl-6u8jXeAPjg,3493
25
- maya_umbrella-0.8.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
26
- maya_umbrella-0.8.0.dist-info/METADATA,sha256=8uNh9uBd18o6IVmFSqXvJRV8bRIPuCQTb8IaC9q_TnM,10996
27
- maya_umbrella-0.8.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
28
- maya_umbrella-0.8.0.dist-info/RECORD,,