accli 2.0.6__tar.gz → 2.0.7__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 (27) hide show
  1. {accli-2.0.6 → accli-2.0.7}/PKG-INFO +1 -1
  2. {accli-2.0.6 → accli-2.0.7}/accli/AcceleratorTaskDispatcher.py +38 -7
  3. {accli-2.0.6 → accli-2.0.7}/accli/_version.py +1 -1
  4. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/PKG-INFO +1 -1
  5. {accli-2.0.6 → accli-2.0.7}/LICENSE +0 -0
  6. {accli-2.0.6 → accli-2.0.7}/README.md +0 -0
  7. {accli-2.0.6 → accli-2.0.7}/accli/AcceleratorJobProjectService.py +0 -0
  8. {accli-2.0.6 → accli-2.0.7}/accli/AcceleratorTerminalCliProjectService.py +0 -0
  9. {accli-2.0.6 → accli-2.0.7}/accli/CsvRegionalTimeseriesValidator.py +0 -0
  10. {accli-2.0.6 → accli-2.0.7}/accli/__init__.py +0 -0
  11. {accli-2.0.6 → accli-2.0.7}/accli/__main__.py +0 -0
  12. {accli-2.0.6 → accli-2.0.7}/accli/cleanup-nfs.ps1 +0 -0
  13. {accli-2.0.6 → accli-2.0.7}/accli/cli.py +0 -0
  14. {accli-2.0.6 → accli-2.0.7}/accli/common.py +0 -0
  15. {accli-2.0.6 → accli-2.0.7}/accli/gui.py +0 -0
  16. {accli-2.0.6 → accli-2.0.7}/accli/mount_downloader.py +0 -0
  17. {accli-2.0.6 → accli-2.0.7}/accli/nfs_watcher.py +0 -0
  18. {accli-2.0.6 → accli-2.0.7}/accli/refresh_explorer.ps1 +0 -0
  19. {accli-2.0.6 → accli-2.0.7}/accli/setup-nfs.ps1 +0 -0
  20. {accli-2.0.6 → accli-2.0.7}/accli/token.py +0 -0
  21. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/SOURCES.txt +0 -0
  22. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/dependency_links.txt +0 -0
  23. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/entry_points.txt +0 -0
  24. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/requires.txt +0 -0
  25. {accli-2.0.6 → accli-2.0.7}/accli.egg-info/top_level.txt +0 -0
  26. {accli-2.0.6 → accli-2.0.7}/pyproject.toml +0 -0
  27. {accli-2.0.6 → accli-2.0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: accli
3
- Version: 2.0.6
3
+ Version: 2.0.7
4
4
  Summary: IIASA Accelerator Client
5
5
  Author-email: Wrufesh S <wrufesh@gmail.com>
6
6
  License: The MIT License (MIT)
@@ -3,11 +3,12 @@ import zipfile
3
3
  import hashlib
4
4
  import shutil
5
5
  import tempfile
6
+ import fnmatch
6
7
  from typing import Optional, Dict, List
7
8
 
8
9
  import requests
9
10
  from functools import lru_cache
10
- from pydantic import BaseModel, model_validator
11
+ from pydantic import BaseModel, model_validator, Field
11
12
  from accli.AcceleratorTerminalCliProjectService import AcceleratorTerminalCliProjectService
12
13
  from accli.token import (
13
14
  get_token, get_server_url,
@@ -48,23 +49,38 @@ def get_file_sha1(file_path):
48
49
  return sha1_hash.hexdigest()
49
50
 
50
51
 
51
- def copy_tree(src, dst):
52
+ def copy_tree(src, dst, include=None, exclude=None, root_src=None):
52
53
  """Recursively copy from src to dst, excluding .git folders."""
54
+ if root_src is None:
55
+ root_src = src
53
56
  for item in os.listdir(src):
54
57
  src_path = os.path.join(src, item)
55
58
  dst_path = os.path.join(dst, item)
59
+ rel_path = os.path.relpath(src_path, root_src)
56
60
 
57
61
  if os.path.isdir(src_path):
58
62
  if item == '.git':
59
63
  continue
64
+ if exclude:
65
+ excludes = [e.strip() for e in exclude.split(',') if e.strip()]
66
+ if any(fnmatch.fnmatch(rel_path, p) or fnmatch.fnmatch(item, p) for p in excludes):
67
+ continue
60
68
  os.makedirs(dst_path, exist_ok=True)
61
- copy_tree(src_path, dst_path)
69
+ copy_tree(src_path, dst_path, include, exclude, root_src)
62
70
  else:
71
+ if exclude:
72
+ excludes = [e.strip() for e in exclude.split(',') if e.strip()]
73
+ if any(fnmatch.fnmatch(rel_path, p) or fnmatch.fnmatch(item, p) for p in excludes):
74
+ continue
75
+ if include:
76
+ includes = [i.strip() for i in include.split(',') if i.strip()]
77
+ if not any(fnmatch.fnmatch(rel_path, p) or fnmatch.fnmatch(item, p) for p in includes):
78
+ continue
63
79
  shutil.copy2(src_path, dst_path)
64
80
 
65
81
 
66
82
  @lru_cache(maxsize=None)
67
- def push_folder_job(directory):
83
+ def push_folder_job(directory, include=None, exclude=None):
68
84
  server_url = get_server_url()
69
85
  project_slug = get_project_slug()
70
86
  _, access_token, _ = exchange_refresh_token(project_slug)
@@ -76,7 +92,7 @@ def push_folder_job(directory):
76
92
  )
77
93
 
78
94
  repo_dir = tempfile.mkdtemp()
79
- copy_tree(directory, repo_dir)
95
+ copy_tree(directory, repo_dir, include, exclude)
80
96
 
81
97
  if os.path.isfile(f'{repo_dir}/wkube.py'):
82
98
  os.remove(f'{repo_dir}/wkube.py')
@@ -152,7 +168,9 @@ class WKubeTaskMeta(BaseModel):
152
168
  class WKubeTaskKwargs(BaseModel):
153
169
  docker_image: Optional[str] = None
154
170
 
155
- job_folder: str = './'
171
+ job_folder: str = Field('./', description="Path to the directory containing job files. Must be a valid existing directory.")
172
+ include: Optional[str] = Field(None, description="Comma-separated wildcard patterns to include (e.g. '*.py, data/*')")
173
+ exclude: Optional[str] = Field(None, description="Comma-separated wildcard patterns to exclude (e.g. '*.txt, .venv/*')")
156
174
 
157
175
  repo_url: Optional[str] = None # required when docker image is not present
158
176
  repo_branch: Optional[str] = None # required when docker image is not present
@@ -172,6 +190,10 @@ class WKubeTaskKwargs(BaseModel):
172
190
  result = super().model_dump(*args, **kwargs)
173
191
  if 'job_folder' in result:
174
192
  del result['job_folder']
193
+ if 'include' in result:
194
+ del result['include']
195
+ if 'exclude' in result:
196
+ del result['exclude']
175
197
  return result
176
198
 
177
199
  @model_validator(mode="before")
@@ -179,10 +201,19 @@ class WKubeTaskKwargs(BaseModel):
179
201
  def validate_root(cls, values):
180
202
  if not values.get('docker_image'):
181
203
  job_folder = values.get('job_folder', './')
204
+ include = values.get('include')
205
+ exclude = values.get('exclude')
206
+
207
+ if not os.path.isdir(job_folder):
208
+ raise ValueError(
209
+ f"Invalid job_folder: '{job_folder}' does not exist or is not a directory. "
210
+ f"Help: job_folder must be a valid path. You can also use 'include' and 'exclude' "
211
+ f"with comma-separated wildcards (e.g., include='*.py, data/*', exclude='*.txt, .venv/*')."
212
+ )
182
213
 
183
214
  if not (values.get('repo_url') and values.get('repo_branch')):
184
215
  remote_url, branch_name = push_folder_job(
185
- os.path.abspath(job_folder)
216
+ os.path.abspath(job_folder), include, exclude
186
217
  )
187
218
  values['repo_url'] = remote_url
188
219
  values['repo_branch'] = branch_name
@@ -1,3 +1,3 @@
1
1
  # Please strictly put double quote to use this info for git tag
2
2
  # Read a developer guide for git tag command with regex
3
- VERSION = "v2.0.6"
3
+ VERSION = "v2.0.7"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: accli
3
- Version: 2.0.6
3
+ Version: 2.0.7
4
4
  Summary: IIASA Accelerator Client
5
5
  Author-email: Wrufesh S <wrufesh@gmail.com>
6
6
  License: The MIT License (MIT)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes