Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
168 changes: 159 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,165 @@
# Byte-compiled / optimized / DLL files
*__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.idea/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# ruff
.ruff_cache/
.venv/
build/
coverage/
dist/

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

# macOS
*.DS_Store

# VSCode
.vscode/

# Project-specific
/coverage/
pytest.ini
docs/contributors/_autosummary/
docs/reference/_autosummary/
htmlcov/
.coverage
.DS_Store
.vscode
53 changes: 53 additions & 0 deletions src/jamf_pro_sdk/clients/jcds2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging
import math
import warnings
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import TYPE_CHECKING, Callable, Iterator, Union
Expand Down Expand Up @@ -134,9 +135,55 @@ def _upload_part(s3_client, multipart_upload: dict, part_number: int, file_uploa
logger.debug(part_resp)
return {"PartNumber": part_number, "ETag": part_resp["ETag"]}

def upload_package(self, file_path: Union[str, Path]) -> None:
"""Upload a file and create the package object using the new package upload API.

This method replaces :meth:`upload_file` and does not require the ``aws`` extra dependency.
It uses the ``POST /v1/packages/{id}/upload`` endpoint instead of the deprecated JCDS v1
S3-based workflow.

A ``JCDS2FileExistsError`` is raised if any file of the same name exists and is associated
to a package.

:param file_path: The path to the file to upload. Will raise ``FileNotFoundError`` if the
path to the file's location does not exist.
:type file_path: Union[str, Path]
"""
if not isinstance(file_path, Path):
file_path = Path(file_path)

if not file_path.exists():
raise FileNotFoundError(f"File not found: {file_path}")

packages = [
self.classic_api_client.get_package_by_id(p)
for p in self.classic_api_client.list_all_packages()
]

for p in packages:
if file_path.name == p.filename:
raise JCDS2FileExistsError(
f"The file '{file_path.name}' exists and is associated to package "
f"({p.id}) '{p.name}'"
)

new_package = ClassicPackage(name=file_path.name, filename=file_path.name)
new_pkg_id = self.classic_api_client.create_package(data=new_package)
logger.debug("Created package %s", new_pkg_id)

try:
self.pro_api_client.upload_package_v1(package_id=new_pkg_id, file_path=file_path)
except Exception as err:
logger.exception(err)
raise

def upload_file(self, file_path: Union[str, Path]) -> None:
"""Upload a file to the JCDS and create the package object.

.. deprecated::
The JCDS v1 API is deprecated by Jamf (2025-08-28). Use :meth:`upload_package` instead,
which does not require the ``aws`` extra dependency.

If the file is less than 1 GiB in size the upload will be performed in a single request. If
the file is greater than 1 GiB in size a multipart upload operation will be performed.

Expand All @@ -151,6 +198,12 @@ def upload_file(self, file_path: Union[str, Path]) -> None:
to the file's location does not exist.
:type file_path: Union[str, Path]
"""
warnings.warn(
"upload_file() is deprecated. The JCDS v1 API was deprecated by Jamf on 2025-08-28. "
"Use upload_package() instead, which does not require the 'aws' extra dependency.",
DeprecationWarning,
stacklevel=2,
)
if not BOTO3_IS_INSTALLED:
raise ImportError("The 'aws' extra dependency is required.")

Expand Down
Loading