UEPyScripts 1.2.4__tar.gz → 1.2.6__tar.gz

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.
Files changed (31) hide show
  1. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/PKG-INFO +26 -2
  2. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/README.md +25 -1
  3. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/internal/engine.py +6 -4
  4. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/internal/engine_resolver.py +14 -9
  5. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/internal/project.py +7 -4
  6. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/helpers.py +1 -4
  7. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/check_engine_installation.py +7 -1
  8. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/.gitignore +0 -0
  9. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/LICENSE +0 -0
  10. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/pyproject.toml +0 -0
  11. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/__init__.py +0 -0
  12. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/context/__init__.py +0 -0
  13. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/internal/__init__.py +0 -0
  14. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/internal/config.py +0 -0
  15. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/run/__init__.py +0 -0
  16. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/run/buildgraph.py +0 -0
  17. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/run/uat.py +0 -0
  18. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/run/ubt.py +0 -0
  19. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/__init__.py +0 -0
  20. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ci/buildgraph.py +0 -0
  21. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ci/cleanup.py +0 -0
  22. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/subprocess.py +0 -0
  23. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/__init__.py +0 -0
  24. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/close_editor.py +0 -0
  25. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/compile_editor.py +0 -0
  26. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/engine_installation/engine_destination.py +0 -0
  27. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/engine_installation/engine_installer.py +0 -0
  28. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/engine_installation/engine_source.py +0 -0
  29. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/generate_solution.py +0 -0
  30. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/ue/run_editor.py +0 -0
  31. {uepyscripts-1.2.4 → uepyscripts-1.2.6}/src/uepyscripts/tools/winreg.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UEPyScripts
3
- Version: 1.2.4
3
+ Version: 1.2.6
4
4
  Summary: Collection of Python tools and helpers designed to automate common Unreal Engine project tasks (builds, packaging, editor control, CI tasks, etc.).
5
5
  Project-URL: Changelog, https://github.com/TheEmidee/UEPyScripts/releases
6
6
  Project-URL: Homepage, https://github.com/TheEmidee/UEPyScripts
@@ -248,6 +248,27 @@ How the script works:
248
248
  .\setup-venv.ps1
249
249
  ```
250
250
 
251
+ - In VS Code, you can create a `launch.json` file like this one. It's important to use the `module` setting so that relative imports don't raise exceptions.
252
+
253
+ ```
254
+ {
255
+ "version": "0.2.0",
256
+ "configurations": [
257
+ {
258
+ "name": "Python Debugger: Current File",
259
+ "type": "debugpy",
260
+ "request": "launch",
261
+ "module": "uepyscripts.tools.ue.copy_engine_buildgraph_tasks",
262
+ "cwd": "ABSOLUTE_PATH_TO_PROJECT",
263
+ "console": "integratedTerminal",
264
+ "args": [
265
+ "--uproject_path=D:\\PATH_TO_UPROJECT.uproject"
266
+ ]
267
+ }
268
+ ]
269
+ }
270
+ ```
271
+
251
272
  - Linting & formatting
252
273
  - Use `uv run ruff check .` and `uv run ruff format .` Add checks to CI as required.
253
274
  - Use `uv run mypy .`
@@ -262,8 +283,11 @@ We welcome contributions — please follow these steps:
262
283
 
263
284
  1. Fork the repository
264
285
  2. Create a feature branch: `git checkout -b feature/your-change`
286
+ 3. Add entries in the .changelog folder for towncrier. You can read the [README](.changelog/README.md) file for more information.
265
287
  4. Run lint locally
266
- 5. Submit a pull request describing the change
288
+ 5. Update documentation
289
+ 6. Submit a pull request describing the change
290
+
267
291
 
268
292
  ---
269
293
 
@@ -168,6 +168,27 @@ How the script works:
168
168
  .\setup-venv.ps1
169
169
  ```
170
170
 
171
+ - In VS Code, you can create a `launch.json` file like this one. It's important to use the `module` setting so that relative imports don't raise exceptions.
172
+
173
+ ```
174
+ {
175
+ "version": "0.2.0",
176
+ "configurations": [
177
+ {
178
+ "name": "Python Debugger: Current File",
179
+ "type": "debugpy",
180
+ "request": "launch",
181
+ "module": "uepyscripts.tools.ue.copy_engine_buildgraph_tasks",
182
+ "cwd": "ABSOLUTE_PATH_TO_PROJECT",
183
+ "console": "integratedTerminal",
184
+ "args": [
185
+ "--uproject_path=D:\\PATH_TO_UPROJECT.uproject"
186
+ ]
187
+ }
188
+ ]
189
+ }
190
+ ```
191
+
171
192
  - Linting & formatting
172
193
  - Use `uv run ruff check .` and `uv run ruff format .` Add checks to CI as required.
173
194
  - Use `uv run mypy .`
@@ -182,8 +203,11 @@ We welcome contributions — please follow these steps:
182
203
 
183
204
  1. Fork the repository
184
205
  2. Create a feature branch: `git checkout -b feature/your-change`
206
+ 3. Add entries in the .changelog folder for towncrier. You can read the [README](.changelog/README.md) file for more information.
185
207
  4. Run lint locally
186
- 5. Submit a pull request describing the change
208
+ 5. Update documentation
209
+ 6. Submit a pull request describing the change
210
+
187
211
 
188
212
  ---
189
213
 
@@ -47,12 +47,14 @@ class Engine:
47
47
  self.project = project
48
48
  self.root_path = root_path
49
49
  self.path = self.root_path.joinpath("Engine").resolve()
50
+ self.build_path = self.path.joinpath("Build").resolve()
51
+ self.batchfiles_path = self.build_path.joinpath("BatchFiles").resolve()
50
52
  self.version = self.get_version_number()
51
- self.uat_path = self.Runner(self.path.joinpath("Build/BatchFiles/RunUAT.bat"), True)
53
+ self.uat_path = self.Runner(self.batchfiles_path.joinpath("RunUAT.bat"), True)
52
54
  self.ubt_path = self.Runner(
53
55
  self.path.joinpath("Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe"), True, True, [str(self.project.uproject_path)]
54
56
  )
55
- self.build_bat_path = self.Runner(self.path.joinpath("Build/BatchFiles/Build.bat"), True)
57
+ self.build_bat_path = self.Runner(self.batchfiles_path.joinpath("Build.bat"), True)
56
58
  self.editor_exe_path = self.Runner(self.path.joinpath("Binaries/Win64/UnrealEditor.exe"), False, False, [str(self.project.uproject_path)])
57
59
 
58
60
  def uat(self, args: list[str] = []) -> int:
@@ -70,7 +72,7 @@ class Engine:
70
72
  def get_version_number(self) -> Version:
71
73
  version = ""
72
74
 
73
- with open(self.path.joinpath("Build/Build.version")) as build_version_file:
75
+ with open(self.build_path.joinpath("Build.version")) as build_version_file:
74
76
  version_json = json.load(build_version_file)
75
77
  major = version_json["MajorVersion"]
76
78
  minor = version_json["MinorVersion"]
@@ -80,7 +82,7 @@ class Engine:
80
82
  if version == "":
81
83
  raise Exception("Impossible to find the version number of the engine")
82
84
 
83
- jenkins_file = Path(self.path.joinpath("Build/JenkinsBuild.version"))
85
+ jenkins_file = Path(self.build_path.joinpath("JenkinsBuild.version"))
84
86
 
85
87
  if jenkins_file.exists():
86
88
  with open(jenkins_file) as jenkins_version_file:
@@ -5,6 +5,7 @@ from typing import Optional
5
5
 
6
6
  from pydantic import BaseModel
7
7
 
8
+ from .. import logger
8
9
  from ..internal.project import Project
9
10
  from ..tools.helpers import get_engine_root_folder_from_env_var, is_engine_from_egs
10
11
  from ..tools.winreg import get_registry_value
@@ -17,9 +18,7 @@ def resolve_engine_from_env_var(project: Project) -> Optional[Path]:
17
18
  def resolve_engine_from_registry(project: Project) -> Optional[Path]:
18
19
  path = get_registry_value(winreg.HKEY_CURRENT_USER, r"SOFTWARE\Epic Games\Unreal Engine\Builds", project.engine_association)
19
20
  if path:
20
- path = Path(path)
21
- if path.exists():
22
- return path
21
+ return Path(path)
23
22
 
24
23
  return None
25
24
 
@@ -30,9 +29,7 @@ def resolve_engine_from_egs(project: Project) -> Optional[Path]:
30
29
  winreg.HKEY_LOCAL_MACHINE, rf"SOFTWARE\EpicGames\Unreal Engine\{project.engine_association}", "InstalledDirectory"
31
30
  )
32
31
  if registry_value:
33
- path = Path(registry_value)
34
- if path.exists():
35
- return path
32
+ return Path(registry_value)
36
33
 
37
34
  # Some installations are listed in LauncherInstalled.dat
38
35
  class EpicInstallation(BaseModel):
@@ -69,13 +66,16 @@ def resolve_engine_from_egs(project: Project) -> Optional[Path]:
69
66
  return Path(item.InstallLocation)
70
67
 
71
68
  except Exception as e:
72
- print(f"Error parsing manifest: {e}")
69
+ logger.error(f"Error parsing manifest: {e}")
73
70
 
74
71
  return None
75
72
 
76
73
 
77
74
  def resolve_engine_from_path(project: Project) -> Optional[Path]:
78
75
  path = Path(project.engine_association)
76
+ if not os.path.isabs(path):
77
+ path = (project.root_folder / path).resolve()
78
+
79
79
  if os.path.isabs(path):
80
80
  return path
81
81
 
@@ -84,20 +84,25 @@ def resolve_engine_from_path(project: Project) -> Optional[Path]:
84
84
 
85
85
  def resolve_engine_path(project: Project) -> Path:
86
86
  resolvers = [
87
- resolve_engine_from_env_var,
88
87
  resolve_engine_from_registry,
89
88
  resolve_engine_from_egs,
90
89
  resolve_engine_from_path,
90
+ # Resolve last with the environment variable to avoid failing the resolution on a machine
91
+ # where there's the environment variable but the engine is installed using the launcher
92
+ resolve_engine_from_env_var,
91
93
  ]
92
94
 
93
95
  for resolver in resolvers:
94
96
  path = resolver(project)
95
97
  if path:
98
+ logger.info(f"Engine path resolved via '{resolver.__name__}': {path}")
96
99
  break
97
100
  else:
98
101
  raise FileNotFoundError("Impossible to locate the engine")
99
102
 
100
- if not (path.exists() and str(path).replace(" ", "") not in ["", ".", "\\"]):
103
+ path_str = str(path).strip()
104
+ # Check that the path exists and is not a degenerate path containing only . or \\
105
+ if not (path.exists() and path_str not in ["", ".", "\\"]):
101
106
  raise FileNotFoundError("Impossible to locate the engine")
102
107
 
103
108
  return path
@@ -68,11 +68,14 @@ def find_parent_with_project_file(starting_path: Path, max_parents: int = 10) ->
68
68
  return None
69
69
 
70
70
 
71
- def resolve_project() -> Project:
72
- dir_path = Path(os.path.dirname(os.path.realpath(__file__)))
73
- uproject_path = find_parent_with_project_file(dir_path)
71
+ def resolve_project(uproject_path: Optional[Path] = None) -> Project:
74
72
  if not uproject_path:
75
- raise Exception(f"Could not find a uproject file from {dir_path}")
73
+ dir_path = Path(os.path.dirname(os.path.realpath(__file__)))
74
+ uproject_path = find_parent_with_project_file(dir_path)
75
+ if not uproject_path:
76
+ raise Exception(f"Could not find a uproject file from {dir_path}")
77
+ elif not uproject_path.exists():
78
+ raise Exception(f"{uproject_path} is not a valid file")
76
79
 
77
80
  logger.debug(f"Found uproject file at {uproject_path}")
78
81
  project = Project(uproject_path)
@@ -32,10 +32,7 @@ def get_engine_root_folder_from_env_var(project_engine_association: str) -> Opti
32
32
  path = Path(node_ue_root)
33
33
  if project_engine_association:
34
34
  path = path.joinpath(project_engine_association)
35
- if path.exists():
36
- return path
37
-
38
- raise FileNotFoundError(f"The environment variable is set to {node_ue_root} but the folder {path} does not exist")
35
+ return path
39
36
 
40
37
  return None
41
38
 
@@ -16,6 +16,7 @@ which is useful when executed on a build pipeline like Jenkins or Horde.
16
16
  """
17
17
 
18
18
  import argparse
19
+ from pathlib import Path
19
20
 
20
21
  from ... import logger
21
22
  from ...internal.engine import resolve_engine
@@ -26,6 +27,11 @@ from ...tools.ue.engine_installation.engine_installer import EngineInstaller
26
27
  def parse_arguments() -> argparse.Namespace:
27
28
  """Parse command line arguments."""
28
29
  parser = argparse.ArgumentParser(description="Check and install Unreal Engine installation for the given project.")
30
+ parser.add_argument(
31
+ "--uproject_path",
32
+ type=Path,
33
+ help=("Optional path to a uproject file.If not set, resolve_project will try to find one in its folder hierarchy"),
34
+ )
29
35
  parser.add_argument("--unattended", action="store_true", help="Disable interactive prompts")
30
36
 
31
37
  return parser.parse_args()
@@ -37,7 +43,7 @@ def main() -> None:
37
43
  args = parse_arguments()
38
44
 
39
45
  try:
40
- project = resolve_project()
46
+ project = resolve_project(args.uproject_path)
41
47
  except Exception as e:
42
48
  logger.fatal(f"Project resolution failed: {e}")
43
49
  exit(1)
File without changes
File without changes
File without changes