File size: 5,061 Bytes
2592ab2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719a7ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2592ab2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
from fastapi import HTTPException


class APIError(HTTPException):
    def __init__(self, status_code: int, code: str, message: str, hint: str | None = None):
        detail = {"error": {"code": code, "message": message}}
        if hint is not None:
            detail["error"]["hint"] = hint
        super().__init__(status_code=status_code, detail=detail)


class InvalidPath(APIError):
    def __init__(self, message: str, hint: str | None = None):
        super().__init__(400, "INVALID_PATH", message, hint)


class InvalidQuery(APIError):
    def __init__(self, message: str, hint: str | None = None):
        super().__init__(400, "INVALID_QUERY", message, hint)


class NotFound(APIError):
    def __init__(self, path: str):
        super().__init__(404, "NOT_FOUND", f"no such file: {path}")


class InvalidFrontmatter(APIError):
    def __init__(self, message: str):
        super().__init__(400, "INVALID_FRONTMATTER", message)


class BodyOrSourceRequired(APIError):
    def __init__(self, message: str = "exactly one of `source` or `body` must be provided"):
        super().__init__(400, "BODY_OR_SOURCE_REQUIRED", message)


class BucketNotOwnedByCaller(APIError):
    def __init__(self, message: str, hint: str | None = None):
        super().__init__(403, "BUCKET_NOT_OWNED_BY_CALLER", message, hint)


class IdentityMismatch(APIError):
    def __init__(self, message: str):
        super().__init__(403, "IDENTITY_MISMATCH", message)


class NotRegistered(APIError):
    def __init__(self, agent_id: str):
        super().__init__(
            404,
            "NOT_REGISTERED",
            f"agent '{agent_id}' is not registered",
            "register first via POST /v1/agents/register",
        )


class SourceNotFound(APIError):
    def __init__(self, uri: str):
        super().__init__(404, "SOURCE_NOT_FOUND", f"source not found: {uri}")


class AgentIdTaken(APIError):
    def __init__(self, agent_id: str):
        super().__init__(
            409,
            "AGENT_ID_TAKEN",
            f"agent_id '{agent_id}' is already registered to another hf_user",
            "pick a different agent_id",
        )


class TaskforceNotFound(APIError):
    def __init__(self, name: str):
        super().__init__(
            404,
            "TASKFORCE_NOT_FOUND",
            f"no such taskforce: '{name}'",
            "create it via POST /v1/taskforces with the name and README content; "
            "GET /v1/taskforces lists what exists",
        )


class TaskforceExists(APIError):
    def __init__(self, name: str, creator: str | None):
        super().__init__(
            409,
            "TASKFORCE_EXISTS",
            f"taskforce '{name}' already exists"
            + (f" (creator: {creator})" if creator else ""),
            "only the creator can update the README; contribute via "
            f"POST /v1/taskforces/{name}/files, or pick another name",
        )


class AlreadyPromoted(APIError):
    def __init__(self, existing_filename: str):
        super().__init__(
            409,
            "ALREADY_PROMOTED",
            "identical content was already promoted",
            f"existing filename: {existing_filename}",
        )


class BucketMissing(APIError):
    def __init__(self, bucket: str):
        super().__init__(
            412,
            "BUCKET_MISSING",
            f"scratch bucket '{bucket}' does not exist",
            f"run: hf buckets create {bucket}",
        )


class SyncTooLarge(APIError):
    def __init__(self, message: str):
        super().__init__(413, "SYNC_TOO_LARGE", message)


class RateLimited(APIError):
    def __init__(self, retry_after_seconds: int, message: str | None = None):
        super().__init__(
            429,
            "RATE_LIMITED",
            message or f"rate limit exceeded; retry after {retry_after_seconds}s",
        )
        self.headers = {"Retry-After": str(retry_after_seconds)}


class Unauthorized(APIError):
    def __init__(self, message: str, hint: str | None = None):
        super().__init__(401, "UNAUTHORIZED", message, hint)


class JobsDisabled(APIError):
    def __init__(self) -> None:
        super().__init__(
            404,
            "JOBS_DISABLED",
            "benchmark jobs are not enabled for this challenge",
            "the organizers can enable them via JOBS_ENABLED=true",
        )


class JobLaunchFailed(APIError):
    def __init__(self, message: str):
        super().__init__(
            502,
            "JOB_LAUNCH_FAILED",
            f"could not launch the benchmark job: {message}",
            "this is a server/credits/permission issue, not your submission; "
            "retry shortly or contact the organizers",
        )


class QuotaBackendUnavailable(APIError):
    def __init__(self) -> None:
        super().__init__(
            503,
            "QUOTA_BACKEND_UNAVAILABLE",
            "could not verify the job quota (quota storage temporarily "
            "unavailable); no job was launched",
            "retry shortly",
        )
        self.headers = {"Retry-After": "30"}