Skip to content

Commit bae3525

Browse files
committed
wip docs & cleanup
1 parent 069b44b commit bae3525

File tree

7 files changed

+159
-20
lines changed

7 files changed

+159
-20
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const PAGES_REFERENCE = [
6565
"reference/job-submission.md",
6666
"reference/jobs.md",
6767
"reference/datasets.md",
68+
"reference/projects.md",
6869
"reference/exceptions.md",
6970
]
7071
Mocking.apply(mocking_patch) do

docs/src/reference/exceptions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ InvalidRequestError
2424
JuliaHubConnectionError
2525
JuliaHubError
2626
PermissionError
27+
ProjectNotSetError
28+
InvalidJuliaHubVersion
2729
```
2830

2931
## Index

docs/src/reference/projects.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
```@meta
2+
CurrentModule=JuliaHub
3+
```
4+
5+
# Projects
6+
7+
These APIs allow you to interact with datasets that have been attached to projects.
8+
9+
* [`project_datasets`](@ref) and [`project_dataset`](@ref) let you list and access datasets linked to a project
10+
* [`upload_project_dataset`](@ref) allows uploading new versions of project-linked datasets
11+
12+
## Automatic project authentication
13+
14+
The [`Authentication`](@ref) object can be associated with a default project UUID, which will
15+
then be used to for all _project_ operations, unless an explicit `project` gets passed to
16+
override the default.
17+
18+
Importantly, [`JuliaHub.authenticate`](@ref) will automatically pick up the the JuliaHub
19+
project UUID from the `JULIAHUB_PROJECT_UUID` environment variable. This means in JuliaHub
20+
cloud jobs and IDEs, it is not necessary to manually set the project, and JuliaHub.jl
21+
will automatically.
22+
However, you can opt-out of this behavior by explicitly passing a `project=nothing` to
23+
[`JuliaHub.authenticate`](@ref).
24+
25+
If you explicitly
26+
27+
you can always pass `project=
28+
29+
- `JULIAHUB_PROJECT_UUID`
30+
31+
You can always verify that your operations are running in the context of the correct project
32+
by checking the [`Authentication`](@ref) object, e.g. via [`current_authentication`](@ref):
33+
34+
```wip-jldoctest
35+
julia> JuliaHub.current_authentication()
36+
...
37+
```
38+
39+
## Reference
40+
41+
```@docs
42+
ProjectDataset
43+
project_datasets
44+
project_dataset
45+
upload_project_dataset
46+
ProjectReference
47+
```
48+
49+
## Index
50+
51+
```@index
52+
Pages = ["project_datasets.md"]
53+
```

src/authentication.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ end
168168
server::AbstractString = Pkg.pkg_server();
169169
force::Bool = false,
170170
maxcount::Integer = $(_DEFAULT_authenticate_maxcount),
171+
[project::Union{AbstractString, UUIDs.UUID, Nothing}],
171172
[hook::Base.Callable]
172173
) -> JuliaHub.Authentication
173174
JuliaHub.authenticate(server::AbstractString, token::Union{AbstractString, JuliaHub.Secret}) -> JuliaHub.Authentication
@@ -201,6 +202,33 @@ The returned [`Authentication`](@ref) object is also cached globally (overwritin
201202
cached authentications), making it unnecessary to pass the returned object manually to other
202203
function calls. This is useful for interactive use, but should not be used in library code,
203204
as different authentication calls may clash.
205+
206+
# Project Context
207+
208+
An [`Authentication`](@ref) object can also specify the default JuliaHub project.
209+
This can be set by passing the optional `project` argument, which works as follows:
210+
211+
- If the `project` value is not passed, JuliaHub.jl will attempt to pick up the the project UUID
212+
from the `JULIAHUB_PROJECT_UUID` environment variable, and will fall back to the non-project
213+
context if that is not set.
214+
215+
- If you pass an explicit UUID (either as a string or an `UUID` object), that will then be used
216+
as the project. Note that a UUID passed as a string must be a syntactically correct UUID.
217+
218+
- If you pass `nothing`, that make JuliaHub.jl ignore any values in the `JULIAHUB_PROJECT_UUID`
219+
environment variable.
220+
221+
!!! note "JULIAHUB_PROJECT_UUID"
222+
223+
Generally, in JuliaHub jobs and cloud IDE environments that are launched in the context of a
224+
project, the `JULIAHUB_PROJECT_UUID` is automatically set, and JuliaHub.jl will pick it up
225+
automatically, unless explicitly disabled with `project=nothing`.
226+
227+
!!! warn "Project access checks"
228+
229+
When the [`Authentication`](@ref) object is constructed, access to or existence of the specified
230+
project is not checked. However, if you attempt any project operations with with such an
231+
authentication object, they will fail and throw an error.
204232
"""
205233
function authenticate end
206234

src/datasets.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
const _DOCS_nondynamic_datasets_object_warning = """
22
!!! warning "Non-dynamic dataset objects"
33
4-
[`Dataset`](@ref) objects represents the dataset metadata when the Julia object was created
5-
(e.g. with [`dataset`](@ref)), and are not automatically kept up to date. To refresh the dataset
6-
metadata, you can pass the existing [`Dataset`](@ref) to [`JuliaHub.dataset`](@ref).
4+
[`Dataset`](@ref) and [`ProjectDataset`](@ref) objects represents the dataset metadata when the
5+
Julia object was created (e.g. with [`dataset`](@ref)), and are not automatically kept up to date.
6+
To refresh the dataset metadata, you can pass the existing [`Dataset`](@ref) to [`JuliaHub.dataset`](@ref),
7+
or [`ProjectDataset`](@ref) to [`project_dataset`](@ref).
78
"""
89

910
Base.@kwdef struct _DatasetStorage

src/projects.jl

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
1+
"""
2+
struct ProjectNotSetError <: JuliaHubException
3+
4+
Exception thrown when the authentication object is not set to a project, nor was
5+
an explicit project UUID provided, but the operation requires a project to be
6+
specified.
7+
"""
8+
struct ProjectNotSetError <: JuliaHubException end
9+
10+
function Base.showerror(io::IO, e::ProjectNotSetError)
11+
print(io, "ProjectNotSetError: authentication object not associated with a project")
12+
end
13+
14+
function _assert_projects_enabled(auth::Authentication)
15+
# The different project APIs are only present in JuliaHub 6.9 and later.
16+
if auth._api_version < v"0.2.0"
17+
msg = "Project APIs got added in JuliaHub 6.9 (expected API version >= 0.2.0, got $(auth._api_version), for $(auth.server))"
18+
throw(InvalidJuliaHubVersion(msg))
19+
end
20+
end
21+
122
"""
223
struct ProjectDataset
324
425
A dataset object returned by the functions that return project dataset links.
526
6-
Has the same fields as [`Dataset`](@ref) plus the following fields
7-
that are specific to the project-dataset link:
27+
Has the same fields as [`Dataset`](@ref) plus the following fields that are specific
28+
to project-dataset links:
829
930
- `project_uuid::UUID`: identifies the project in the context of which the dataset was listed
1031
- `is_writable :: Bool`: whether this dataset has been marked writable by the dataset owner
@@ -53,20 +74,20 @@ function Base.show(io::IO, ::MIME"text/plain", pd::ProjectDataset)
5374
end
5475

5576
"""
56-
struct ProjectNotSetError <: JuliaHubException
77+
const ProjectReference :: Type
5778
58-
Exception thrown when the authentication object is not set to a project, but the
59-
operation is meant to take place in the context of a project.
60-
"""
61-
struct ProjectNotSetError <: JuliaHubException end
62-
function Base.showerror(io::IO, e::ProjectNotSetError)
63-
print(io, "ProjectNotSetError: authentication object not associated with a project")
64-
end
79+
Type constraint on the argument that specifies the project in projects-related
80+
APIs that (e.g. [`project_datasets`](@ref)).
6581
82+
Presently, you can specify the project by directly passing the project UUID.
83+
The UUID should be either a string (`<: AbstractString`) or an `UUIDs.UUID` object.
84+
"""
6685
const ProjectReference = Union{AbstractString, UUIDs.UUID}
6786

6887
# Parses the standard project::Union{ProjectReference, Nothing} we pass to
6988
# project_* function into a project UUID object (or throws the appropriate error).
89+
# If project is nothing, we fall back to the project_id of the authentication object,
90+
# if present.
7091
function _project_uuid(auth::Authentication, project::Union{ProjectReference, Nothing})::UUIDs.UUID
7192
if isnothing(project)
7293
if isnothing(auth.project_id)
@@ -88,17 +109,22 @@ function _project_uuid(auth::Authentication, project::Union{ProjectReference, No
88109
end
89110

90111
"""
91-
JuliaHub.project_dataset(dataset::DatasetReference; [project::ProjectReference], [auth]) -> Dataset
112+
JuliaHub.project_dataset(dataset::DatasetReference; [project::ProjectReference], [auth]) -> ProjectDataset
113+
114+
Looks up the specified dataset among the datasets attached to the project, returning a
115+
[`ProjectDataset`](@ref) object, or throwing an [`InvalidRequestError`](@ref) if the project
116+
does not have the dataset attached.
92117
93-
Looks up a dataset in the context of a project.
118+
$(_DOCS_nondynamic_datasets_object_warning)
94119
"""
95120
function project_dataset end
96121

97122
function project_dataset(
98-
dataset::Dataset;
123+
dataset::Union{Dataset, ProjectDataset};
99124
project::Union{ProjectReference, Nothing}=nothing,
100125
auth::Authentication=__auth__(),
101126
)
127+
_assert_projects_enabled(auth)
102128
project_uuid = _project_uuid(auth, project)
103129
datasets = _project_datasets(auth, project_uuid)
104130
for project_dataset in datasets
@@ -142,9 +168,10 @@ function project_dataset(
142168
end
143169

144170
"""
145-
JuliaHub.project_datasets([project::Union{AbstractString, UUID}]; [auth::Authentication]) -> Vector{Dataset}
171+
JuliaHub.project_datasets([project::ProjectReference]; [auth::Authentication]) -> Vector{Dataset}
146172
147-
Returns the list of datasets linked to the given project.
173+
Returns the list of datasets attached to the project, as a list of [`ProjectDataset`](@ref) objects.
174+
If the project is not explicitly specified, it uses the project of the authentication object.
148175
"""
149176
function project_datasets end
150177

@@ -239,7 +266,7 @@ Uploads a new version of a project-linked dataset.
239266
function upload_project_dataset end
240267

241268
function upload_project_dataset(
242-
ds::Dataset,
269+
ds::Union{Dataset, ProjectDataset},
243270
local_path::AbstractString;
244271
progress::Bool=true,
245272
project::Union{ProjectReference, Nothing}=nothing,
@@ -281,8 +308,16 @@ function upload_project_dataset(
281308
end
282309

283310
function upload_project_dataset(
284-
::Union{_DatasetRefTuple, AbstractString}
311+
dataset::Union{_DatasetRefTuple, AbstractString},
312+
local_path::AbstractString;
313+
progress::Bool=true,
314+
project::Union{ProjectReference, Nothing}=nothing,
315+
# Authentication
316+
auth::Authentication=__auth__(),
285317
)
318+
project_uuid = _project_uuid(auth, project)
319+
dataset = project_dataset(dataset; project=project_uuid, auth)
320+
return upload_project_dataset(dataset, local_path; progress, project=project_uuid, auth)
286321
end
287322

288323
# This calls the /datasets/{uuid}/versions?project={uuid} endpoint,

src/utils.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,25 @@ function Base.showerror(io::IO, e::PermissionError)
9494
isnothing(e.response) || print(io, '\n', e.response)
9595
end
9696

97+
"""
98+
struct InvalidJuliaHubVersion <: JuliaHubException
99+
100+
Thrown if the requested operation is not supported by the JuliaHub instance.
101+
`.msg` contains a more detailed error message.
102+
103+
!!! tip
104+
105+
This generally means that the functionality you are attempting to use requires a
106+
newer JuliaHub version.
107+
"""
108+
struct InvalidJuliaHubVersion <: JuliaHubException
109+
msg::String
110+
end
111+
112+
function Base.showerror(io::IO, e::InvalidJuliaHubVersion)
113+
print(io, "InvalidJuliaHubVersion: $(e.msg)")
114+
end
115+
97116
_takebody!(r::HTTP.Response)::Vector{UInt8} = isa(r.body, IO) ? take!(r.body) : r.body
98117
_takebody!(r::HTTP.Response, ::Type{T}) where {T} = T(_takebody!(r))
99118

0 commit comments

Comments
 (0)