Skip to content

Commit

Permalink
Update build script and change log; put kagglesdk in src
Browse files Browse the repository at this point in the history
  • Loading branch information
stevemessick committed Jan 14, 2025
1 parent 2435811 commit b8de057
Show file tree
Hide file tree
Showing 66 changed files with 15,296 additions and 8 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
Changelog
====
### 1.7

* Remove Swagger. No user-visible changes to the command-line tool. However, projects that
use `kaggle/api/kaggle_api.py` may be affected. That file is deprecated and will be removed.
Most of it functions still work, but those that involve uploading files no longer work.
The command-line tool uses a higher-level abstraction for uploading and client code needs
to be converted to use that.

### 1.6.17

* No changes; release 1.6.16 did not complete.
Expand Down
2 changes: 1 addition & 1 deletion kaggle/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
# Copyright 2024 Kaggle Inc
# Copyright 2025 Kaggle Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml → pyproject.xtoml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ dependencies = [
"pytest",
]

[tool.setuptools.packages.find]
where = ["src"]
include = ["kaggle*"]
namespaces = false

[tool.hatch.envs.default.scripts]
install-unzip = """sudo apt-get install -y unzip || echo 'unzip could not be installed'"""
install-autogen = """curl -fsSL --output /tmp/autogen.zip "https://github.com/mbrukman/autogen/archive/refs/heads/master.zip" &&
Expand Down
9 changes: 6 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# pyproject.toml instead of maintaining both flows.
setup(
name='kaggle',
version='1.6.17',
version='1.7',
description='Kaggle API',
long_description=(
'Official API for https://www.kaggle.com, accessible using a command line '
Expand All @@ -26,5 +26,8 @@
'six >= 1.10', 'certifi >= 2023.7.22', 'python-dateutil', 'requests',
'tqdm', 'python-slugify', 'urllib3', 'bleach', 'protobuf'
],
packages=find_packages(exclude=("src.*", "src")),
license='Apache 2.0')
packages=find_packages(
where='src',
include=['kaggle*'],
),
package_dir={"": "src"})
2 changes: 1 addition & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.6.17"
__version__ = "1.7"
Empty file added src/kaggle/api/__init__.py
Empty file.
Empty file added src/kaggle/models/__init__.py
Empty file.
2 changes: 2 additions & 0 deletions src/kagglesdk/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from kagglesdk.kaggle_client import KaggleClient
from kagglesdk.kaggle_env import KaggleEnv
Empty file added src/kagglesdk/admin/__init__.py
Empty file.
Empty file.
26 changes: 26 additions & 0 deletions src/kagglesdk/admin/services/inbox_file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from kagglesdk.admin.types.inbox_file_service import CreateInboxFileRequest, CreateInboxFileResponse
from kagglesdk.kaggle_http_client import KaggleHttpClient


class InboxFileClient(object):
"""File drop/pickup functionality."""

def __init__(self, client: KaggleHttpClient):
self._client = client

def create_inbox_file(self,
request: CreateInboxFileRequest = None
) -> CreateInboxFileResponse:
r"""
Creates (aka 'drops') a new file into the inbox.
Args:
request (CreateInboxFileRequest):
The request object; initialized to empty instance if not specified.
"""

if request is None:
request = CreateInboxFileRequest()

return self._client.call("admin.InboxFileService", "CreateInboxFile",
request, CreateInboxFileResponse)
Empty file.
76 changes: 76 additions & 0 deletions src/kagglesdk/admin/types/inbox_file_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from kagglesdk.kaggle_object import *


class CreateInboxFileRequest(KaggleObject):
r"""
Attributes:
virtual_directory (str)
Directory name used for tagging the uploaded file.
blob_file_token (str)
Token representing the uploaded file.
"""

def __init__(self):
self._virtual_directory = ""
self._blob_file_token = ""
self._freeze()

@property
def virtual_directory(self) -> str:
"""Directory name used for tagging the uploaded file."""
return self._virtual_directory

@virtual_directory.setter
def virtual_directory(self, virtual_directory: str):
if virtual_directory is None:
del self.virtual_directory
return
if not isinstance(virtual_directory, str):
raise TypeError('virtual_directory must be of type str')
self._virtual_directory = virtual_directory

@property
def blob_file_token(self) -> str:
"""Token representing the uploaded file."""
return self._blob_file_token

@blob_file_token.setter
def blob_file_token(self, blob_file_token: str):
if blob_file_token is None:
del self.blob_file_token
return
if not isinstance(blob_file_token, str):
raise TypeError('blob_file_token must be of type str')
self._blob_file_token = blob_file_token

def endpoint(self):
path = '/api/v1/inbox/files/create'
return path.format_map(self.to_field_map(self))

@staticmethod
def method():
return 'POST'

@staticmethod
def body_fields():
return '*'


class CreateInboxFileResponse(KaggleObject):
r"""
NOTE: This is sent to non-admins, so we're intentionally *NOT* sending back
the full InboxFile (with its URL for a direct download).
"""

pass


CreateInboxFileRequest._fields = [
FieldMetadata("virtualDirectory", "virtual_directory", "_virtual_directory",
str, "", PredefinedSerializer()),
FieldMetadata("blobFileToken", "blob_file_token", "_blob_file_token", str,
"", PredefinedSerializer()),
]

CreateInboxFileResponse._fields = []
Empty file added src/kagglesdk/blobs/__init__.py
Empty file.
Empty file.
29 changes: 29 additions & 0 deletions src/kagglesdk/blobs/services/blob_api_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from kagglesdk.blobs.types.blob_api_service import ApiStartBlobUploadRequest, ApiStartBlobUploadResponse
from kagglesdk.kaggle_http_client import KaggleHttpClient


class BlobApiClient(object):
r"""
Binary Large OBject (BLOB) service used for uploading files to Google Cloud
Storage (GCS).
"""

def __init__(self, client: KaggleHttpClient):
self._client = client

def start_blob_upload(
self,
request: ApiStartBlobUploadRequest = None) -> ApiStartBlobUploadResponse:
r"""
Starts a blob upload (i.e. reserves a spot for the upload on GCS).
Args:
request (ApiStartBlobUploadRequest):
The request object; initialized to empty instance if not specified.
"""

if request is None:
request = ApiStartBlobUploadRequest()

return self._client.call("blobs.BlobApiService", "ApiStartBlobUpload",
request, ApiStartBlobUploadResponse)
Empty file.
190 changes: 190 additions & 0 deletions src/kagglesdk/blobs/types/blob_api_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import enum
from kagglesdk.kaggle_object import *
from typing import Optional


class ApiBlobType(enum.Enum):
API_BLOB_TYPE_UNSPECIFIED = 0
DATASET = 1
MODEL = 2
INBOX = 3


class ApiStartBlobUploadRequest(KaggleObject):
r"""
Attributes:
type (ApiBlobType)
The type of the blob.
name (str)
Name (e.g. file name) of the blob.
content_type (str)
Content/MIME type (e.g. 'text/plain').
content_length (int)
Size in bytes of the blob.
last_modified_epoch_seconds (int)
Optional user-reported time when the blob was last updated/modified.
"""

def __init__(self):
self._type = ApiBlobType.API_BLOB_TYPE_UNSPECIFIED
self._name = ""
self._content_type = None
self._content_length = 0
self._last_modified_epoch_seconds = None
self._freeze()

@property
def type(self) -> 'ApiBlobType':
"""The type of the blob."""
return self._type

@type.setter
def type(self, type: 'ApiBlobType'):
if type is None:
del self.type
return
if not isinstance(type, ApiBlobType):
raise TypeError('type must be of type ApiBlobType')
self._type = type

@property
def name(self) -> str:
"""Name (e.g. file name) of the blob."""
return self._name

@name.setter
def name(self, name: str):
if name is None:
del self.name
return
if not isinstance(name, str):
raise TypeError('name must be of type str')
self._name = name

@property
def content_type(self) -> str:
"""Content/MIME type (e.g. 'text/plain')."""
return self._content_type or ""

@content_type.setter
def content_type(self, content_type: str):
if content_type is None:
del self.content_type
return
if not isinstance(content_type, str):
raise TypeError('content_type must be of type str')
self._content_type = content_type

@property
def content_length(self) -> int:
"""Size in bytes of the blob."""
return self._content_length

@content_length.setter
def content_length(self, content_length: int):
if content_length is None:
del self.content_length
return
if not isinstance(content_length, int):
raise TypeError('content_length must be of type int')
self._content_length = content_length

@property
def last_modified_epoch_seconds(self) -> int:
"""Optional user-reported time when the blob was last updated/modified."""
return self._last_modified_epoch_seconds or 0

@last_modified_epoch_seconds.setter
def last_modified_epoch_seconds(self, last_modified_epoch_seconds: int):
if last_modified_epoch_seconds is None:
del self.last_modified_epoch_seconds
return
if not isinstance(last_modified_epoch_seconds, int):
raise TypeError('last_modified_epoch_seconds must be of type int')
self._last_modified_epoch_seconds = last_modified_epoch_seconds

def endpoint(self):
path = '/api/v1/blobs/upload'
return path.format_map(self.to_field_map(self))

@staticmethod
def method():
return 'POST'

@staticmethod
def body_fields():
return '*'


class ApiStartBlobUploadResponse(KaggleObject):
r"""
Attributes:
token (str)
Opaque string token used to reference the new blob/file.
create_url (str)
URL to use to start the upload.
"""

def __init__(self):
self._token = ""
self._create_url = ""
self._freeze()

@property
def token(self) -> str:
"""Opaque string token used to reference the new blob/file."""
return self._token

@token.setter
def token(self, token: str):
if token is None:
del self.token
return
if not isinstance(token, str):
raise TypeError('token must be of type str')
self._token = token

@property
def create_url(self) -> str:
"""URL to use to start the upload."""
return self._create_url

@create_url.setter
def create_url(self, create_url: str):
if create_url is None:
del self.create_url
return
if not isinstance(create_url, str):
raise TypeError('create_url must be of type str')
self._create_url = create_url


ApiStartBlobUploadRequest._fields = [
FieldMetadata("type", "type", "_type", ApiBlobType,
ApiBlobType.API_BLOB_TYPE_UNSPECIFIED, EnumSerializer()),
FieldMetadata("name", "name", "_name", str, "", PredefinedSerializer()),
FieldMetadata(
"contentType",
"content_type",
"_content_type",
str,
None,
PredefinedSerializer(),
optional=True),
FieldMetadata("contentLength", "content_length", "_content_length", int, 0,
PredefinedSerializer()),
FieldMetadata(
"lastModifiedEpochSeconds",
"last_modified_epoch_seconds",
"_last_modified_epoch_seconds",
int,
None,
PredefinedSerializer(),
optional=True),
]

ApiStartBlobUploadResponse._fields = [
FieldMetadata("token", "token", "_token", str, "", PredefinedSerializer()),
FieldMetadata("createUrl", "create_url", "_create_url", str, "",
PredefinedSerializer()),
]
Empty file.
Empty file.
Loading

0 comments on commit b8de057

Please sign in to comment.