durable_huggingface_hub 0.2.0
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.
- checksums.yaml +7 -0
- data/.editorconfig +29 -0
- data/.rubocop.yml +108 -0
- data/CHANGELOG.md +127 -0
- data/README.md +547 -0
- data/Rakefile +106 -0
- data/devenv.lock +171 -0
- data/devenv.nix +15 -0
- data/devenv.yaml +8 -0
- data/huggingface_hub.gemspec +63 -0
- data/lib/durable_huggingface_hub/authentication.rb +245 -0
- data/lib/durable_huggingface_hub/cache.rb +508 -0
- data/lib/durable_huggingface_hub/configuration.rb +191 -0
- data/lib/durable_huggingface_hub/constants.rb +145 -0
- data/lib/durable_huggingface_hub/errors.rb +412 -0
- data/lib/durable_huggingface_hub/file_download.rb +831 -0
- data/lib/durable_huggingface_hub/hf_api.rb +1278 -0
- data/lib/durable_huggingface_hub/repo_card.rb +430 -0
- data/lib/durable_huggingface_hub/types/cache_info.rb +298 -0
- data/lib/durable_huggingface_hub/types/commit_info.rb +149 -0
- data/lib/durable_huggingface_hub/types/dataset_info.rb +158 -0
- data/lib/durable_huggingface_hub/types/model_info.rb +154 -0
- data/lib/durable_huggingface_hub/types/space_info.rb +158 -0
- data/lib/durable_huggingface_hub/types/user.rb +179 -0
- data/lib/durable_huggingface_hub/types.rb +205 -0
- data/lib/durable_huggingface_hub/utils/auth.rb +174 -0
- data/lib/durable_huggingface_hub/utils/headers.rb +220 -0
- data/lib/durable_huggingface_hub/utils/http.rb +329 -0
- data/lib/durable_huggingface_hub/utils/paths.rb +230 -0
- data/lib/durable_huggingface_hub/utils/progress.rb +217 -0
- data/lib/durable_huggingface_hub/utils/retry.rb +165 -0
- data/lib/durable_huggingface_hub/utils/validators.rb +236 -0
- data/lib/durable_huggingface_hub/version.rb +8 -0
- data/lib/huggingface_hub.rb +205 -0
- metadata +334 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../types"
|
|
4
|
+
|
|
5
|
+
module DurableHuggingfaceHub
|
|
6
|
+
module Types
|
|
7
|
+
# Information about a model repository on HuggingFace Hub.
|
|
8
|
+
#
|
|
9
|
+
# This structure represents metadata about a model, including its ID,
|
|
10
|
+
# tags, files, statistics, and configuration.
|
|
11
|
+
#
|
|
12
|
+
# @example Creating a ModelInfo from API response
|
|
13
|
+
# model_info = ModelInfo.from_hash({
|
|
14
|
+
# "id" => "bert-base-uncased",
|
|
15
|
+
# "sha" => "a1b2c3d4...",
|
|
16
|
+
# "tags" => ["transformers", "pytorch"],
|
|
17
|
+
# "downloads" => 1000000,
|
|
18
|
+
# "likes" => 500
|
|
19
|
+
# })
|
|
20
|
+
#
|
|
21
|
+
# @example Accessing model information
|
|
22
|
+
# model_info.id # => "bert-base-uncased"
|
|
23
|
+
# model_info.tags # => ["transformers", "pytorch"]
|
|
24
|
+
# model_info.downloads # => 1000000
|
|
25
|
+
class ModelInfo < DurableHuggingfaceHub::Struct
|
|
26
|
+
include Loadable
|
|
27
|
+
|
|
28
|
+
# @!attribute [r] id
|
|
29
|
+
# @return [String] Model repository ID (e.g., "bert-base-uncased")
|
|
30
|
+
attribute :id, Types::RepoId
|
|
31
|
+
|
|
32
|
+
# @!attribute [r] sha
|
|
33
|
+
# @return [String, nil] Git commit SHA of the current revision
|
|
34
|
+
attribute :sha, Types::OptionalString.default(nil)
|
|
35
|
+
|
|
36
|
+
# @!attribute [r] last_modified
|
|
37
|
+
# @return [Time, nil] Timestamp of last modification
|
|
38
|
+
attribute :last_modified, Types::OptionalTimestamp.default(nil)
|
|
39
|
+
|
|
40
|
+
# @!attribute [r] tags
|
|
41
|
+
# @return [Array<String>] Tags associated with the model
|
|
42
|
+
attribute :tags, Types::StringArray.default([].freeze)
|
|
43
|
+
|
|
44
|
+
# @!attribute [r] pipeline_tag
|
|
45
|
+
# @return [String, nil] Primary pipeline/task tag (e.g., "text-classification")
|
|
46
|
+
attribute :pipeline_tag, Types::OptionalString.default(nil)
|
|
47
|
+
|
|
48
|
+
# @!attribute [r] siblings
|
|
49
|
+
# @return [Array<Hash>, nil] List of files in the repository
|
|
50
|
+
attribute :siblings, Types::OptionalFileSiblings.default(nil)
|
|
51
|
+
|
|
52
|
+
# @!attribute [r] private
|
|
53
|
+
# @return [Boolean, nil] Whether the repository is private
|
|
54
|
+
attribute :private, Types::OptionalBool.default(nil)
|
|
55
|
+
|
|
56
|
+
# @!attribute [r] gated
|
|
57
|
+
# @return [Boolean, String, nil] Gated access status (false, "auto", "manual")
|
|
58
|
+
attribute :gated, Types::OptionalGated.default(nil)
|
|
59
|
+
|
|
60
|
+
# @!attribute [r] disabled
|
|
61
|
+
# @return [Boolean, nil] Whether the repository is disabled
|
|
62
|
+
attribute :disabled, Types::OptionalBool.default(nil)
|
|
63
|
+
|
|
64
|
+
# @!attribute [r] downloads
|
|
65
|
+
# @return [Integer, nil] Total number of downloads
|
|
66
|
+
attribute :downloads, Types::OptionalInteger.default(nil)
|
|
67
|
+
|
|
68
|
+
# @!attribute [r] likes
|
|
69
|
+
# @return [Integer, nil] Number of likes/stars
|
|
70
|
+
attribute :likes, Types::OptionalInteger.default(nil)
|
|
71
|
+
|
|
72
|
+
# @!attribute [r] library_name
|
|
73
|
+
# @return [String, nil] Primary library (e.g., "transformers", "diffusers")
|
|
74
|
+
attribute :library_name, Types::OptionalString.default(nil)
|
|
75
|
+
|
|
76
|
+
# @!attribute [r] config
|
|
77
|
+
# @return [Hash, nil] Model configuration data
|
|
78
|
+
attribute :config, Types::OptionalHash.default(nil)
|
|
79
|
+
|
|
80
|
+
# @!attribute [r] author
|
|
81
|
+
# @return [String, nil] Author/organization name
|
|
82
|
+
attribute :author, Types::OptionalString.default(nil)
|
|
83
|
+
|
|
84
|
+
# @!attribute [r] created_at
|
|
85
|
+
# @return [Time, nil] Repository creation timestamp
|
|
86
|
+
attribute :created_at, Types::OptionalTimestamp.default(nil)
|
|
87
|
+
|
|
88
|
+
# @!attribute [r] card_data
|
|
89
|
+
# @return [Hash, nil] Model card metadata
|
|
90
|
+
attribute :card_data, Types::OptionalHash.default(nil)
|
|
91
|
+
|
|
92
|
+
# Returns the list of file names in the repository.
|
|
93
|
+
#
|
|
94
|
+
# @return [Array<String>] File names
|
|
95
|
+
def file_names
|
|
96
|
+
return [] if siblings.nil?
|
|
97
|
+
|
|
98
|
+
siblings.map { |s| s[:rfilename] || s["rfilename"] }.compact
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Checks if the model has a specific tag.
|
|
102
|
+
#
|
|
103
|
+
# @param tag [String] Tag to check for
|
|
104
|
+
# @return [Boolean] True if the tag is present
|
|
105
|
+
def has_tag?(tag)
|
|
106
|
+
tags.include?(tag)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Checks if the repository is public.
|
|
110
|
+
#
|
|
111
|
+
# @return [Boolean] True if public (not private)
|
|
112
|
+
def public?
|
|
113
|
+
!private
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Checks if the repository is gated.
|
|
117
|
+
#
|
|
118
|
+
# @return [Boolean] True if gated
|
|
119
|
+
def gated?
|
|
120
|
+
case gated
|
|
121
|
+
when true, "auto", "manual"
|
|
122
|
+
true
|
|
123
|
+
else
|
|
124
|
+
false
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Checks if the repository is disabled.
|
|
129
|
+
#
|
|
130
|
+
# @return [Boolean] True if disabled
|
|
131
|
+
def disabled?
|
|
132
|
+
disabled == true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Returns a short description of the model.
|
|
136
|
+
#
|
|
137
|
+
# @return [String] Description string
|
|
138
|
+
def to_s
|
|
139
|
+
parts = [id]
|
|
140
|
+
parts << "(#{pipeline_tag})" if pipeline_tag
|
|
141
|
+
parts << "[#{library_name}]" if library_name
|
|
142
|
+
parts.join(" ")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns a detailed inspection string.
|
|
146
|
+
#
|
|
147
|
+
# @return [String] Inspection string
|
|
148
|
+
def inspect
|
|
149
|
+
"#<#{self.class.name} id=#{id.inspect} sha=#{sha&.[](0, 7).inspect} " \
|
|
150
|
+
"tags=#{tags.size} files=#{siblings&.size || 0}>"
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../types"
|
|
4
|
+
|
|
5
|
+
module DurableHuggingfaceHub
|
|
6
|
+
module Types
|
|
7
|
+
# Information about a Space repository on HuggingFace Hub.
|
|
8
|
+
#
|
|
9
|
+
# Spaces are interactive ML demos and applications hosted on HuggingFace Hub.
|
|
10
|
+
#
|
|
11
|
+
# @example Creating a SpaceInfo from API response
|
|
12
|
+
# space_info = SpaceInfo.from_hash({
|
|
13
|
+
# "id" => "gradio/hello-world",
|
|
14
|
+
# "sdk" => "gradio",
|
|
15
|
+
# "tags" => ["gradio", "demo"],
|
|
16
|
+
# "likes" => 100
|
|
17
|
+
# })
|
|
18
|
+
#
|
|
19
|
+
# @example Accessing space information
|
|
20
|
+
# space_info.id # => "gradio/hello-world"
|
|
21
|
+
# space_info.sdk # => "gradio"
|
|
22
|
+
# space_info.runtime # => {"stage" => "RUNNING"}
|
|
23
|
+
class SpaceInfo < DurableHuggingfaceHub::Struct
|
|
24
|
+
include Loadable
|
|
25
|
+
|
|
26
|
+
# @!attribute [r] id
|
|
27
|
+
# @return [String] Space repository ID
|
|
28
|
+
attribute :id, Types::RepoId
|
|
29
|
+
|
|
30
|
+
# @!attribute [r] sha
|
|
31
|
+
# @return [String, nil] Git commit SHA of the current revision
|
|
32
|
+
attribute :sha, Types::OptionalString.default(nil)
|
|
33
|
+
|
|
34
|
+
# @!attribute [r] last_modified
|
|
35
|
+
# @return [Time, nil] Timestamp of last modification
|
|
36
|
+
attribute :last_modified, Types::OptionalTimestamp.default(nil)
|
|
37
|
+
|
|
38
|
+
# @!attribute [r] tags
|
|
39
|
+
# @return [Array<String>] Tags associated with the space
|
|
40
|
+
attribute :tags, Types::StringArray.default([].freeze)
|
|
41
|
+
|
|
42
|
+
# @!attribute [r] siblings
|
|
43
|
+
# @return [Array<Hash>, nil] List of files in the repository
|
|
44
|
+
attribute :siblings, Types::OptionalFileSiblings.default(nil)
|
|
45
|
+
|
|
46
|
+
# @!attribute [r] private
|
|
47
|
+
# @return [Boolean, nil] Whether the repository is private
|
|
48
|
+
attribute :private, Types::OptionalBool.default(nil)
|
|
49
|
+
|
|
50
|
+
# @!attribute [r] gated
|
|
51
|
+
# @return [Boolean, String, nil] Gated access status
|
|
52
|
+
attribute :gated, Types::OptionalGated.default(nil)
|
|
53
|
+
|
|
54
|
+
# @!attribute [r] disabled
|
|
55
|
+
# @return [Boolean, nil] Whether the repository is disabled
|
|
56
|
+
attribute :disabled, Types::OptionalBool.default(nil)
|
|
57
|
+
|
|
58
|
+
# @!attribute [r] likes
|
|
59
|
+
# @return [Integer, nil] Number of likes/stars
|
|
60
|
+
attribute :likes, Types::OptionalInteger.default(nil)
|
|
61
|
+
|
|
62
|
+
# @!attribute [r] author
|
|
63
|
+
# @return [String, nil] Author/organization name
|
|
64
|
+
attribute :author, Types::OptionalString.default(nil)
|
|
65
|
+
|
|
66
|
+
# @!attribute [r] created_at
|
|
67
|
+
# @return [Time, nil] Repository creation timestamp
|
|
68
|
+
attribute :created_at, Types::OptionalTimestamp.default(nil)
|
|
69
|
+
|
|
70
|
+
# @!attribute [r] sdk
|
|
71
|
+
# @return [String, nil] SDK used (e.g., "gradio", "streamlit", "static")
|
|
72
|
+
attribute :sdk, Types::OptionalString.default(nil)
|
|
73
|
+
|
|
74
|
+
# @!attribute [r] runtime
|
|
75
|
+
# @return [Hash, nil] Runtime information (stage, hardware, etc.)
|
|
76
|
+
attribute :runtime, Types::OptionalHash.default(nil)
|
|
77
|
+
|
|
78
|
+
# @!attribute [r] card_data
|
|
79
|
+
# @return [Hash, nil] Space card metadata
|
|
80
|
+
attribute :card_data, Types::OptionalHash.default(nil)
|
|
81
|
+
|
|
82
|
+
# Returns the list of file names in the repository.
|
|
83
|
+
#
|
|
84
|
+
# @return [Array<String>] File names
|
|
85
|
+
def file_names
|
|
86
|
+
return [] if siblings.nil?
|
|
87
|
+
|
|
88
|
+
siblings.map { |s| s[:rfilename] || s["rfilename"] }.compact
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Checks if the space has a specific tag.
|
|
92
|
+
#
|
|
93
|
+
# @param tag [String] Tag to check for
|
|
94
|
+
# @return [Boolean] True if the tag is present
|
|
95
|
+
def has_tag?(tag)
|
|
96
|
+
tags.include?(tag)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Checks if the repository is public.
|
|
100
|
+
#
|
|
101
|
+
# @return [Boolean] True if public
|
|
102
|
+
def public?
|
|
103
|
+
!private
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Checks if the repository is gated.
|
|
107
|
+
#
|
|
108
|
+
# @return [Boolean] True if gated
|
|
109
|
+
def gated?
|
|
110
|
+
case gated
|
|
111
|
+
when true, "auto", "manual"
|
|
112
|
+
true
|
|
113
|
+
else
|
|
114
|
+
false
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Checks if the repository is disabled.
|
|
119
|
+
#
|
|
120
|
+
# @return [Boolean] True if disabled
|
|
121
|
+
def disabled?
|
|
122
|
+
disabled == true
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Returns the runtime stage if available.
|
|
126
|
+
#
|
|
127
|
+
# @return [String, nil] Runtime stage (e.g., "RUNNING", "STOPPED")
|
|
128
|
+
def runtime_stage
|
|
129
|
+
runtime&.dig("stage") || runtime&.dig(:stage)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Checks if the space is currently running.
|
|
133
|
+
#
|
|
134
|
+
# @return [Boolean] True if running
|
|
135
|
+
def running?
|
|
136
|
+
runtime_stage == "RUNNING"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Returns a short description of the space.
|
|
140
|
+
#
|
|
141
|
+
# @return [String] Description string
|
|
142
|
+
def to_s
|
|
143
|
+
parts = [id]
|
|
144
|
+
parts << "(#{sdk})" if sdk
|
|
145
|
+
parts << "[#{runtime_stage}]" if runtime_stage
|
|
146
|
+
parts.join(" ")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns a detailed inspection string.
|
|
150
|
+
#
|
|
151
|
+
# @return [String] Inspection string
|
|
152
|
+
def inspect
|
|
153
|
+
"#<#{self.class.name} id=#{id.inspect} sdk=#{sdk.inspect} " \
|
|
154
|
+
"stage=#{runtime_stage.inspect}>"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../types"
|
|
4
|
+
|
|
5
|
+
module DurableHuggingfaceHub
|
|
6
|
+
module Types
|
|
7
|
+
# Information about a HuggingFace Hub user.
|
|
8
|
+
#
|
|
9
|
+
# @example Creating a User from API response
|
|
10
|
+
# user = User.from_hash({
|
|
11
|
+
# "name" => "john_doe",
|
|
12
|
+
# "fullname" => "John Doe",
|
|
13
|
+
# "email" => "john@example.com",
|
|
14
|
+
# "isPro" => false
|
|
15
|
+
# })
|
|
16
|
+
#
|
|
17
|
+
# @example Accessing user information
|
|
18
|
+
# user.name # => "john_doe"
|
|
19
|
+
# user.fullname # => "John Doe"
|
|
20
|
+
# user.pro? # => false
|
|
21
|
+
class User < DurableHuggingfaceHub::Struct
|
|
22
|
+
include Loadable
|
|
23
|
+
|
|
24
|
+
# @!attribute [r] type
|
|
25
|
+
# @return [String, nil] User type (e.g., "user")
|
|
26
|
+
attribute :type, Types::OptionalString.default(nil)
|
|
27
|
+
|
|
28
|
+
# @!attribute [r] name
|
|
29
|
+
# @return [String] Username
|
|
30
|
+
attribute :name, Types::String
|
|
31
|
+
|
|
32
|
+
# @!attribute [r] fullname
|
|
33
|
+
# @return [String, nil] Full display name
|
|
34
|
+
attribute :fullname, Types::OptionalString.default(nil)
|
|
35
|
+
|
|
36
|
+
# @!attribute [r] email
|
|
37
|
+
# @return [String, nil] Email address
|
|
38
|
+
attribute :email, Types::OptionalString.default(nil)
|
|
39
|
+
|
|
40
|
+
# @!attribute [r] avatar_url
|
|
41
|
+
# @return [String, nil] Avatar image URL
|
|
42
|
+
attribute :avatar_url, Types::OptionalString.default(nil)
|
|
43
|
+
|
|
44
|
+
# @!attribute [r] is_pro
|
|
45
|
+
# @return [Boolean, nil] Whether user has Pro subscription
|
|
46
|
+
attribute :is_pro, Types::OptionalBool.default(nil)
|
|
47
|
+
|
|
48
|
+
# @!attribute [r] orgs
|
|
49
|
+
# @return [Array<Hash>, nil] Organizations the user belongs to
|
|
50
|
+
attribute :orgs, Types::Array.of(Types::Hash).optional.default(nil)
|
|
51
|
+
|
|
52
|
+
# Transform isPro from API to is_pro
|
|
53
|
+
def self.from_hash(data)
|
|
54
|
+
transformed = data.dup
|
|
55
|
+
if transformed.key?("isPro") && !transformed.key?("is_pro")
|
|
56
|
+
transformed["is_pro"] = transformed.delete("isPro")
|
|
57
|
+
elsif transformed.key?(:isPro) && !transformed.key?(:is_pro)
|
|
58
|
+
transformed[:is_pro] = transformed.delete(:isPro)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if transformed.key?("avatarUrl") && !transformed.key?("avatar_url")
|
|
62
|
+
transformed["avatar_url"] = transformed.delete("avatarUrl")
|
|
63
|
+
elsif transformed.key?(:avatarUrl) && !transformed.key?(:avatar_url)
|
|
64
|
+
transformed[:avatar_url] = transformed.delete(:avatarUrl)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
new(transformed)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Checks if the user has a Pro subscription.
|
|
71
|
+
#
|
|
72
|
+
# @return [Boolean] True if Pro user
|
|
73
|
+
def pro?
|
|
74
|
+
is_pro == true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns the display name (fullname if available, otherwise username).
|
|
78
|
+
#
|
|
79
|
+
# @return [String] Display name
|
|
80
|
+
def display_name
|
|
81
|
+
fullname || name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns a short description of the user.
|
|
85
|
+
#
|
|
86
|
+
# @return [String] Description string
|
|
87
|
+
def to_s
|
|
88
|
+
display_name
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns a detailed inspection string.
|
|
92
|
+
#
|
|
93
|
+
# @return [String] Inspection string
|
|
94
|
+
def inspect
|
|
95
|
+
"#<#{self.class.name} name=#{name.inspect} fullname=#{fullname.inspect} pro=#{pro?}>"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Information about a HuggingFace Hub organization.
|
|
100
|
+
#
|
|
101
|
+
# @example Creating an Organization from API response
|
|
102
|
+
# org = Organization.from_hash({
|
|
103
|
+
# "name" => "huggingface",
|
|
104
|
+
# "fullname" => "Hugging Face",
|
|
105
|
+
# "isEnterprise" => true
|
|
106
|
+
# })
|
|
107
|
+
#
|
|
108
|
+
# @example Accessing organization information
|
|
109
|
+
# org.name # => "huggingface"
|
|
110
|
+
# org.fullname # => "Hugging Face"
|
|
111
|
+
# org.enterprise? # => true
|
|
112
|
+
class Organization < DurableHuggingfaceHub::Struct
|
|
113
|
+
include Loadable
|
|
114
|
+
|
|
115
|
+
# @!attribute [r] name
|
|
116
|
+
# @return [String] Organization name/ID
|
|
117
|
+
attribute :name, Types::String
|
|
118
|
+
|
|
119
|
+
# @!attribute [r] fullname
|
|
120
|
+
# @return [String, nil] Full display name
|
|
121
|
+
attribute :fullname, Types::OptionalString.default(nil)
|
|
122
|
+
|
|
123
|
+
# @!attribute [r] avatar_url
|
|
124
|
+
# @return [String, nil] Organization avatar URL
|
|
125
|
+
attribute :avatar_url, Types::OptionalString.default(nil)
|
|
126
|
+
|
|
127
|
+
# @!attribute [r] is_enterprise
|
|
128
|
+
# @return [Boolean, nil] Whether this is an Enterprise organization
|
|
129
|
+
attribute :is_enterprise, Types::OptionalBool.default(nil)
|
|
130
|
+
|
|
131
|
+
# Transform isEnterprise from API to is_enterprise
|
|
132
|
+
def self.from_hash(data)
|
|
133
|
+
transformed = data.dup
|
|
134
|
+
if transformed.key?("isEnterprise") && !transformed.key?("is_enterprise")
|
|
135
|
+
transformed["is_enterprise"] = transformed.delete("isEnterprise")
|
|
136
|
+
elsif transformed.key?(:isEnterprise) && !transformed.key?(:is_enterprise)
|
|
137
|
+
transformed[:is_enterprise] = transformed.delete(:isEnterprise)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if transformed.key?("avatarUrl") && !transformed.key?("avatar_url")
|
|
141
|
+
transformed["avatar_url"] = transformed.delete("avatarUrl")
|
|
142
|
+
elsif transformed.key?(:avatarUrl) && !transformed.key?(:avatar_url)
|
|
143
|
+
transformed[:avatar_url] = transformed.delete(:avatarUrl)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
new(transformed)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Checks if this is an Enterprise organization.
|
|
150
|
+
#
|
|
151
|
+
# @return [Boolean] True if Enterprise
|
|
152
|
+
def enterprise?
|
|
153
|
+
is_enterprise == true
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Returns the display name (fullname if available, otherwise name).
|
|
157
|
+
#
|
|
158
|
+
# @return [String] Display name
|
|
159
|
+
def display_name
|
|
160
|
+
fullname || name
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Returns a short description of the organization.
|
|
164
|
+
#
|
|
165
|
+
# @return [String] Description string
|
|
166
|
+
def to_s
|
|
167
|
+
display_name
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Returns a detailed inspection string.
|
|
171
|
+
#
|
|
172
|
+
# @return [String] Inspection string
|
|
173
|
+
def inspect
|
|
174
|
+
"#<#{self.class.name} name=#{name.inspect} fullname=#{fullname.inspect} " \
|
|
175
|
+
"enterprise=#{enterprise?}>"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dry-types"
|
|
4
|
+
require "dry-struct"
|
|
5
|
+
|
|
6
|
+
module DurableHuggingfaceHub
|
|
7
|
+
# Type definitions and custom types for the HuggingFace Hub client.
|
|
8
|
+
#
|
|
9
|
+
# This module sets up the type system using dry-types and defines
|
|
10
|
+
# custom types for domain-specific validation and coercion.
|
|
11
|
+
#
|
|
12
|
+
# @example Using custom types
|
|
13
|
+
# Types::RepoId["organization/model-name"]
|
|
14
|
+
# Types::RepoType["model"]
|
|
15
|
+
# Types::Revision["main"]
|
|
16
|
+
module Types
|
|
17
|
+
include Dry.Types()
|
|
18
|
+
|
|
19
|
+
# Repository ID type with validation.
|
|
20
|
+
#
|
|
21
|
+
# Valid format: "organization/repository-name" or "username/repository-name"
|
|
22
|
+
# May also be just "repository-name" for models in the user's namespace.
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# Types::RepoId["bert-base-uncased"]
|
|
26
|
+
# Types::RepoId["huggingface/transformers"]
|
|
27
|
+
RepoId = String.constrained(min_size: 1)
|
|
28
|
+
|
|
29
|
+
# Repository type enumeration.
|
|
30
|
+
#
|
|
31
|
+
# Valid values: "model", "dataset", "space"
|
|
32
|
+
#
|
|
33
|
+
# @example
|
|
34
|
+
# Types::RepoType["model"]
|
|
35
|
+
# Types::RepoType["dataset"]
|
|
36
|
+
RepoType = String.enum("model", "dataset", "space")
|
|
37
|
+
|
|
38
|
+
# Revision type (branch, tag, or commit SHA).
|
|
39
|
+
#
|
|
40
|
+
# Can be a branch name (e.g., "main"), tag (e.g., "v1.0.0"),
|
|
41
|
+
# or Git commit SHA (40 hexadecimal characters).
|
|
42
|
+
#
|
|
43
|
+
# @example
|
|
44
|
+
# Types::Revision["main"]
|
|
45
|
+
# Types::Revision["v1.0.0"]
|
|
46
|
+
# Types::Revision["a1b2c3d4e5f6..."]
|
|
47
|
+
Revision = String.constrained(min_size: 1)
|
|
48
|
+
|
|
49
|
+
# Strict boolean type.
|
|
50
|
+
StrictBool = Strict::Bool
|
|
51
|
+
|
|
52
|
+
# Optional string type.
|
|
53
|
+
OptionalString = String.optional
|
|
54
|
+
|
|
55
|
+
# Optional integer type.
|
|
56
|
+
OptionalInteger = Integer.optional
|
|
57
|
+
|
|
58
|
+
# Optional boolean type.
|
|
59
|
+
OptionalBool = Bool.optional
|
|
60
|
+
|
|
61
|
+
# Array of strings type.
|
|
62
|
+
StringArray = Array.of(String)
|
|
63
|
+
|
|
64
|
+
# Optional array of strings type.
|
|
65
|
+
OptionalStringArray = Array.of(String).optional
|
|
66
|
+
|
|
67
|
+
# Hash with string keys type.
|
|
68
|
+
StringHash = Hash.map(String, Any)
|
|
69
|
+
|
|
70
|
+
# Optional hash type.
|
|
71
|
+
OptionalHash = Hash.optional
|
|
72
|
+
|
|
73
|
+
# Timestamp type (Time, DateTime, or ISO 8601 string).
|
|
74
|
+
Timestamp = Time | DateTime | String
|
|
75
|
+
|
|
76
|
+
# Optional timestamp type.
|
|
77
|
+
OptionalTimestamp = Timestamp.optional
|
|
78
|
+
|
|
79
|
+
# File siblings type (array of hashes representing files in a repository).
|
|
80
|
+
FileSiblings = Array.of(Hash)
|
|
81
|
+
|
|
82
|
+
# Optional file siblings type.
|
|
83
|
+
OptionalFileSiblings = FileSiblings.optional
|
|
84
|
+
|
|
85
|
+
# Gated access type (true, false, "auto", "manual").
|
|
86
|
+
GatedType = Bool | String.enum("auto", "manual")
|
|
87
|
+
|
|
88
|
+
# Optional gated type.
|
|
89
|
+
OptionalGated = GatedType.optional
|
|
90
|
+
|
|
91
|
+
# URL type for web addresses.
|
|
92
|
+
#
|
|
93
|
+
# Accepts any string that looks like a URL.
|
|
94
|
+
#
|
|
95
|
+
# @example
|
|
96
|
+
# Types::URL["https://example.com"]
|
|
97
|
+
# Types::URL["http://example.com/path"]
|
|
98
|
+
URL = String.constrained(format: URI::DEFAULT_PARSER.make_regexp)
|
|
99
|
+
|
|
100
|
+
# Optional URL type.
|
|
101
|
+
OptionalURL = URL.optional
|
|
102
|
+
|
|
103
|
+
# Pathname type for file system paths.
|
|
104
|
+
#
|
|
105
|
+
# Accepts strings, Pathname objects, or anything that responds to #to_path or #to_s.
|
|
106
|
+
#
|
|
107
|
+
# @example
|
|
108
|
+
# Types::PathnameType["/path/to/file"]
|
|
109
|
+
# Types::PathnameType[Pathname.new("/path/to/file")]
|
|
110
|
+
PathnameType = Any.constructor do |value|
|
|
111
|
+
case value
|
|
112
|
+
when Pathname
|
|
113
|
+
value
|
|
114
|
+
when String
|
|
115
|
+
Pathname.new(value)
|
|
116
|
+
else
|
|
117
|
+
Pathname.new(value.to_s)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Optional Pathname type.
|
|
122
|
+
OptionalPathnameType = PathnameType.optional
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Autoload type structures
|
|
126
|
+
module Types
|
|
127
|
+
autoload :ModelInfo, "durable_huggingface_hub/types/model_info"
|
|
128
|
+
autoload :DatasetInfo, "durable_huggingface_hub/types/dataset_info"
|
|
129
|
+
autoload :SpaceInfo, "durable_huggingface_hub/types/space_info"
|
|
130
|
+
autoload :CommitInfo, "durable_huggingface_hub/types/commit_info"
|
|
131
|
+
autoload :GitRefInfo, "durable_huggingface_hub/types/commit_info"
|
|
132
|
+
autoload :User, "durable_huggingface_hub/types/user"
|
|
133
|
+
autoload :Organization, "durable_huggingface_hub/types/user"
|
|
134
|
+
autoload :CachedFileInfo, "durable_huggingface_hub/types/cache_info"
|
|
135
|
+
autoload :CachedRevisionInfo, "durable_huggingface_hub/types/cache_info"
|
|
136
|
+
autoload :CachedRepoInfo, "durable_huggingface_hub/types/cache_info"
|
|
137
|
+
autoload :HFCacheInfo, "durable_huggingface_hub/types/cache_info"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Base class for data structures using dry-struct.
|
|
141
|
+
#
|
|
142
|
+
# Provides immutable, type-checked data structures with automatic
|
|
143
|
+
# attribute validation and coercion.
|
|
144
|
+
#
|
|
145
|
+
# @example Defining a data structure
|
|
146
|
+
# class MyData < DurableHuggingfaceHub::Struct
|
|
147
|
+
# attribute :name, Types::String
|
|
148
|
+
# attribute :count, Types::Integer
|
|
149
|
+
# attribute :optional, Types::OptionalString
|
|
150
|
+
# end
|
|
151
|
+
class Struct < Dry::Struct
|
|
152
|
+
# Use type schema for strict attribute validation
|
|
153
|
+
schema schema.strict
|
|
154
|
+
|
|
155
|
+
# Transform attribute keys from camelCase strings to snake_case symbols
|
|
156
|
+
transform_keys do |key|
|
|
157
|
+
# Convert camelCase to snake_case, then to symbol
|
|
158
|
+
key.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Base class for data structures that can be loaded from JSON/Hash.
|
|
162
|
+
#
|
|
163
|
+
# Provides convenient methods for creating instances from API responses.
|
|
164
|
+
module Loadable
|
|
165
|
+
# Creates an instance from a hash (typically from JSON parsing).
|
|
166
|
+
#
|
|
167
|
+
# @param data [Hash] Data hash
|
|
168
|
+
# @return [Struct] New instance
|
|
169
|
+
def self.included(base)
|
|
170
|
+
base.extend(ClassMethods)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
module ClassMethods
|
|
174
|
+
# Creates an instance from a hash.
|
|
175
|
+
#
|
|
176
|
+
# @param data [Hash] Data hash with string or symbol keys
|
|
177
|
+
# @return [self] New instance of the struct
|
|
178
|
+
def from_hash(data)
|
|
179
|
+
new(data)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Alias for from_hash.
|
|
183
|
+
#
|
|
184
|
+
# @param data [Hash] Data hash
|
|
185
|
+
# @return [self] New instance
|
|
186
|
+
alias from_json from_hash
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Converts the struct to a hash.
|
|
190
|
+
#
|
|
191
|
+
# @return [Hash] Hash representation
|
|
192
|
+
def to_h
|
|
193
|
+
attributes.to_h
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Converts the struct to JSON.
|
|
197
|
+
#
|
|
198
|
+
# @return [String] JSON representation
|
|
199
|
+
def to_json(*args)
|
|
200
|
+
require "json"
|
|
201
|
+
to_h.to_json(*args)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|