featrixsphere 0.2.1238__py3-none-any.whl → 0.2.1438__py3-none-any.whl
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.
- featrixsphere/__init__.py +1 -1
- featrixsphere/client.py +116 -70
- {featrixsphere-0.2.1238.dist-info → featrixsphere-0.2.1438.dist-info}/METADATA +1 -1
- featrixsphere-0.2.1438.dist-info/RECORD +9 -0
- featrixsphere-0.2.1238.dist-info/RECORD +0 -9
- {featrixsphere-0.2.1238.dist-info → featrixsphere-0.2.1438.dist-info}/WHEEL +0 -0
- {featrixsphere-0.2.1238.dist-info → featrixsphere-0.2.1438.dist-info}/entry_points.txt +0 -0
- {featrixsphere-0.2.1238.dist-info → featrixsphere-0.2.1438.dist-info}/top_level.txt +0 -0
featrixsphere/__init__.py
CHANGED
featrixsphere/client.py
CHANGED
|
@@ -715,53 +715,101 @@ class FeatrixSphereClient:
|
|
|
715
715
|
except Exception as e:
|
|
716
716
|
return False, f"Error checking foundation model: {e}"
|
|
717
717
|
|
|
718
|
-
def get_model_card(self, session_id: str, max_retries: int = None
|
|
718
|
+
def get_model_card(self, session_id: str, max_retries: int = None) -> Dict[str, Any]:
|
|
719
719
|
"""
|
|
720
720
|
Get the model card JSON for a given session.
|
|
721
721
|
|
|
722
|
+
Handles on-demand model card generation:
|
|
723
|
+
- If model card is being generated (202), waits and retries
|
|
724
|
+
- If model card doesn't exist (404) but session is DONE, retries (on-demand creation may be in progress)
|
|
725
|
+
|
|
722
726
|
Args:
|
|
723
727
|
session_id: The session ID to get the model card for
|
|
724
728
|
max_retries: Maximum number of retries (defaults to client default)
|
|
725
|
-
check_status_first: If True, check session status before fetching model card.
|
|
726
|
-
Provides better error messages if session is still training.
|
|
727
729
|
|
|
728
730
|
Returns:
|
|
729
731
|
Dictionary containing the model card JSON data
|
|
730
732
|
|
|
731
733
|
Raises:
|
|
732
|
-
requests.exceptions.HTTPError: If the request fails
|
|
733
|
-
FileNotFoundError: If the model card doesn't exist (404)
|
|
734
|
-
ValueError: If session is not ready and check_status_first is True
|
|
734
|
+
requests.exceptions.HTTPError: If the request fails after all retries
|
|
735
|
+
FileNotFoundError: If the model card doesn't exist (404) and can't be created
|
|
735
736
|
|
|
736
737
|
Example:
|
|
737
738
|
>>> client = FeatrixSphereClient()
|
|
738
739
|
>>> model_card = client.get_model_card("session_123")
|
|
739
740
|
>>> print(model_card["model_details"]["name"])
|
|
740
741
|
"""
|
|
741
|
-
|
|
742
|
-
|
|
742
|
+
if max_retries is None:
|
|
743
|
+
max_retries = self.default_max_retries
|
|
744
|
+
|
|
745
|
+
# Use a longer retry window for model card requests (on-demand generation can take time)
|
|
746
|
+
max_retry_time = 60.0 # 60 seconds for model card generation
|
|
747
|
+
start_time = time.time()
|
|
748
|
+
attempt = 0
|
|
749
|
+
|
|
750
|
+
while True:
|
|
751
|
+
attempt += 1
|
|
752
|
+
elapsed = time.time() - start_time
|
|
753
|
+
|
|
743
754
|
try:
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
755
|
+
response = self._make_request(
|
|
756
|
+
"GET",
|
|
757
|
+
f"/session/{session_id}/model_card",
|
|
758
|
+
max_retries=1, # Don't use default retries, handle manually
|
|
759
|
+
max_retry_time=None
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
# Check for 202 Accepted (generation in progress)
|
|
763
|
+
if response.status_code == 202:
|
|
764
|
+
response_data = response.json()
|
|
765
|
+
message = response_data.get("message", "Model card generation in progress")
|
|
766
|
+
|
|
767
|
+
# If we have time left, wait and retry
|
|
768
|
+
if elapsed < max_retry_time and attempt <= max_retries:
|
|
769
|
+
wait_time = min(5.0, max_retry_time - elapsed) # Wait up to 5 seconds
|
|
770
|
+
if wait_time > 0:
|
|
771
|
+
print(f"⏳ Model card generation in progress (attempt {attempt}/{max_retries}), waiting {wait_time:.1f}s...")
|
|
772
|
+
time.sleep(wait_time)
|
|
773
|
+
continue
|
|
774
|
+
else:
|
|
775
|
+
# Out of time or retries
|
|
776
|
+
raise requests.exceptions.HTTPError(
|
|
777
|
+
f"Model card generation timed out after {elapsed:.1f}s. {message}",
|
|
778
|
+
response=response
|
|
779
|
+
)
|
|
780
|
+
|
|
781
|
+
# Success - return the model card
|
|
782
|
+
return response.json()
|
|
783
|
+
|
|
751
784
|
except requests.exceptions.HTTPError as e:
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
785
|
+
if e.response is not None and e.response.status_code == 404:
|
|
786
|
+
# 404 - model card doesn't exist
|
|
787
|
+
# Check if we should retry (on-demand generation might be starting)
|
|
788
|
+
if elapsed < max_retry_time and attempt <= max_retries:
|
|
789
|
+
# Check session status to see if it's DONE (model card should exist or be creatable)
|
|
790
|
+
try:
|
|
791
|
+
session_status = self.get_session_status(session_id, max_retries=1)
|
|
792
|
+
if session_status.status in ["done", "DONE"]:
|
|
793
|
+
# Session is done, model card should be creatable - retry after a short delay
|
|
794
|
+
wait_time = min(3.0, max_retry_time - elapsed)
|
|
795
|
+
if wait_time > 0:
|
|
796
|
+
print(f"⏳ Model card not found for DONE session (attempt {attempt}/{max_retries}), retrying in {wait_time:.1f}s (on-demand generation may be starting)...")
|
|
797
|
+
time.sleep(wait_time)
|
|
798
|
+
continue
|
|
799
|
+
except Exception:
|
|
800
|
+
# If we can't check session status, just retry once more
|
|
801
|
+
if attempt <= 2:
|
|
802
|
+
wait_time = min(2.0, max_retry_time - elapsed)
|
|
803
|
+
if wait_time > 0:
|
|
804
|
+
print(f"⏳ Model card not found (attempt {attempt}/{max_retries}), retrying in {wait_time:.1f}s...")
|
|
805
|
+
time.sleep(wait_time)
|
|
806
|
+
continue
|
|
807
|
+
|
|
808
|
+
# Out of retries or session not DONE - raise the 404
|
|
809
|
+
raise FileNotFoundError(f"Model card not found for session {session_id}") from e
|
|
810
|
+
else:
|
|
811
|
+
# Other HTTP errors - re-raise
|
|
812
|
+
raise
|
|
765
813
|
|
|
766
814
|
def publish_session(self, session_id: str) -> Dict[str, Any]:
|
|
767
815
|
"""
|
|
@@ -915,7 +963,7 @@ class FeatrixSphereClient:
|
|
|
915
963
|
|
|
916
964
|
def wait_for_session_completion(self, session_id: str, max_wait_time: int = 3600,
|
|
917
965
|
check_interval: int = 10, show_live_training_movie: bool = None,
|
|
918
|
-
training_interval_movie: int = 3) -> SessionInfo:
|
|
966
|
+
training_interval_movie: int = 3, status_callback: callable = None) -> SessionInfo:
|
|
919
967
|
"""
|
|
920
968
|
Wait for a session to complete, with smart progress display.
|
|
921
969
|
|
|
@@ -926,10 +974,16 @@ class FeatrixSphereClient:
|
|
|
926
974
|
show_live_training_movie: If True, show live training visualization as epochs progress.
|
|
927
975
|
If None, auto-enable in notebook environments (default: None)
|
|
928
976
|
training_interval_movie: Show training movie updates every N epochs (default: 3)
|
|
977
|
+
status_callback: Optional callback function(session_info, elapsed_seconds) called on each status check.
|
|
978
|
+
If provided, uses this instead of default display methods.
|
|
929
979
|
|
|
930
980
|
Returns:
|
|
931
981
|
Final SessionInfo when session completes or times out
|
|
932
982
|
"""
|
|
983
|
+
# If callback provided, use it instead of display methods
|
|
984
|
+
if status_callback is not None:
|
|
985
|
+
return self._wait_with_callback(session_id, max_wait_time, check_interval, status_callback)
|
|
986
|
+
|
|
933
987
|
# Auto-enable live training movie in notebooks if not explicitly set
|
|
934
988
|
if show_live_training_movie is None:
|
|
935
989
|
show_live_training_movie = self._is_notebook()
|
|
@@ -977,6 +1031,14 @@ class FeatrixSphereClient:
|
|
|
977
1031
|
def _wait_with_smart_display(self, session_id: str, max_wait_time: int, check_interval: int, show_live_training_movie: bool = False, training_interval_movie: int = 3) -> SessionInfo:
|
|
978
1032
|
"""Smart progress display that adapts to environment."""
|
|
979
1033
|
|
|
1034
|
+
# Check if we're in a thread (not main thread) - Rich doesn't support multiple live displays
|
|
1035
|
+
import threading
|
|
1036
|
+
is_main_thread = threading.current_thread() is threading.main_thread()
|
|
1037
|
+
|
|
1038
|
+
# If not in main thread, use simple display to avoid Rich LiveError
|
|
1039
|
+
if not is_main_thread:
|
|
1040
|
+
return self._wait_with_simple_display(session_id, max_wait_time, check_interval)
|
|
1041
|
+
|
|
980
1042
|
if self._is_notebook():
|
|
981
1043
|
return self._wait_with_notebook_display(session_id, max_wait_time, check_interval, show_live_training_movie, training_interval_movie)
|
|
982
1044
|
elif self._has_rich():
|
|
@@ -1156,6 +1218,28 @@ class FeatrixSphereClient:
|
|
|
1156
1218
|
# Fallback if rich not available
|
|
1157
1219
|
return self._wait_with_simple_display(session_id, max_wait_time, check_interval)
|
|
1158
1220
|
|
|
1221
|
+
def _wait_with_callback(self, session_id: str, max_wait_time: int, check_interval: int, status_callback: callable) -> SessionInfo:
|
|
1222
|
+
"""Wait for session completion using a custom callback for status updates."""
|
|
1223
|
+
import time
|
|
1224
|
+
|
|
1225
|
+
start_time = time.time()
|
|
1226
|
+
|
|
1227
|
+
while time.time() - start_time < max_wait_time:
|
|
1228
|
+
session_info = self.get_session_status(session_id)
|
|
1229
|
+
elapsed = time.time() - start_time
|
|
1230
|
+
|
|
1231
|
+
# Call the callback with current status
|
|
1232
|
+
status_callback(session_info, elapsed)
|
|
1233
|
+
|
|
1234
|
+
# Check if completed
|
|
1235
|
+
if session_info.status in ['completed', 'done', 'DONE']:
|
|
1236
|
+
return session_info
|
|
1237
|
+
|
|
1238
|
+
time.sleep(check_interval)
|
|
1239
|
+
|
|
1240
|
+
# Timeout - return final status
|
|
1241
|
+
return self.get_session_status(session_id)
|
|
1242
|
+
|
|
1159
1243
|
def _wait_with_simple_display(self, session_id: str, max_wait_time: int, check_interval: int) -> SessionInfo:
|
|
1160
1244
|
"""Simple display with line overwriting for basic terminals."""
|
|
1161
1245
|
import sys
|
|
@@ -4117,7 +4201,6 @@ class FeatrixSphereClient:
|
|
|
4117
4201
|
epochs: int = 0,
|
|
4118
4202
|
rare_label_value: str = None,
|
|
4119
4203
|
class_imbalance: dict = None,
|
|
4120
|
-
optimize_for: str = "balanced",
|
|
4121
4204
|
poll_interval: int = 30, max_poll_time: int = 3600,
|
|
4122
4205
|
verbose: bool = True,
|
|
4123
4206
|
webhooks: Dict[str, str] = None) -> SessionInfo:
|
|
@@ -4140,7 +4223,6 @@ class FeatrixSphereClient:
|
|
|
4140
4223
|
epochs: Number of training epochs (default: 0; automatic)
|
|
4141
4224
|
rare_label_value: For binary classification, which class is the rare/minority class for metrics (default: None)
|
|
4142
4225
|
class_imbalance: Expected class ratios/counts from real world for sampled data (default: None)
|
|
4143
|
-
optimize_for: Optimization target - "balanced" (F1 score), "precision", or "recall" (default: "balanced")
|
|
4144
4226
|
poll_interval: Seconds between status checks when job is already running (default: 30)
|
|
4145
4227
|
max_poll_time: Maximum time to poll in seconds (default: 3600 = 1 hour)
|
|
4146
4228
|
verbose: Whether to print status updates during polling (default: True)
|
|
@@ -4178,7 +4260,6 @@ class FeatrixSphereClient:
|
|
|
4178
4260
|
"target_column": target_column,
|
|
4179
4261
|
"target_column_type": target_column_type,
|
|
4180
4262
|
"epochs": str(epochs),
|
|
4181
|
-
"optimize_for": optimize_for,
|
|
4182
4263
|
}
|
|
4183
4264
|
|
|
4184
4265
|
# Handle file upload - send file directly in multipart form
|
|
@@ -4297,7 +4378,6 @@ class FeatrixSphereClient:
|
|
|
4297
4378
|
validation_ignore_columns: List[str] = None,
|
|
4298
4379
|
rare_label_value: str = None,
|
|
4299
4380
|
class_imbalance: dict = None,
|
|
4300
|
-
optimize_for: str = "balanced",
|
|
4301
4381
|
cost_false_positive: float = None,
|
|
4302
4382
|
cost_false_negative: float = None,
|
|
4303
4383
|
poll_interval: int = 30, max_poll_time: int = 3600,
|
|
@@ -4477,24 +4557,6 @@ class FeatrixSphereClient:
|
|
|
4477
4557
|
This happens automatically - no configuration needed. The system invests a few seconds
|
|
4478
4558
|
in analysis to deliver significantly better models.
|
|
4479
4559
|
|
|
4480
|
-
Understanding optimize_for:
|
|
4481
|
-
---------------------------
|
|
4482
|
-
The optimize_for parameter controls which loss function and training strategy is used,
|
|
4483
|
-
optimizing for different aspects of model performance:
|
|
4484
|
-
|
|
4485
|
-
- "balanced" (default): Optimizes for F1 score (harmonic mean of precision and recall).
|
|
4486
|
-
Uses FocalLoss with class weights. Best for general-purpose classification where you
|
|
4487
|
-
want balanced performance across all classes.
|
|
4488
|
-
|
|
4489
|
-
- "precision": Optimizes for precision (minimizing false positives). Uses FocalLoss with
|
|
4490
|
-
class weights, which focuses training on hard-to-classify examples. Best when false
|
|
4491
|
-
positives are costly (e.g., fraud detection where flagging legitimate transactions
|
|
4492
|
-
as fraud is expensive).
|
|
4493
|
-
|
|
4494
|
-
- "recall": Optimizes for recall (minimizing false negatives). Uses CrossEntropyLoss
|
|
4495
|
-
with class weights that strongly boost the minority class. Best when false negatives
|
|
4496
|
-
are costly (e.g., medical diagnosis where missing a disease is dangerous).
|
|
4497
|
-
|
|
4498
4560
|
Understanding class_imbalance:
|
|
4499
4561
|
------------------------------
|
|
4500
4562
|
For imbalanced datasets where your training data doesn't reflect real-world class
|
|
@@ -4615,7 +4677,6 @@ class FeatrixSphereClient:
|
|
|
4615
4677
|
target_column='approved',
|
|
4616
4678
|
target_column_type='set',
|
|
4617
4679
|
class_imbalance={'approved': 0.97, 'rejected': 0.03},
|
|
4618
|
-
optimize_for='recall', # Don't miss rejections
|
|
4619
4680
|
rare_label_value='rejected'
|
|
4620
4681
|
)
|
|
4621
4682
|
|
|
@@ -4636,7 +4697,6 @@ class FeatrixSphereClient:
|
|
|
4636
4697
|
target_column='is_fraud',
|
|
4637
4698
|
target_column_type='set',
|
|
4638
4699
|
rare_label_value='fraud',
|
|
4639
|
-
optimize_for='precision', # Minimize false alarms
|
|
4640
4700
|
class_imbalance={'legitimate': 0.999, 'fraud': 0.001}
|
|
4641
4701
|
)
|
|
4642
4702
|
```
|
|
@@ -4650,8 +4710,7 @@ class FeatrixSphereClient:
|
|
|
4650
4710
|
session_id=session.session_id,
|
|
4651
4711
|
target_column='has_disease',
|
|
4652
4712
|
target_column_type='set',
|
|
4653
|
-
rare_label_value='positive'
|
|
4654
|
-
optimize_for='recall' # Don't miss any cases
|
|
4713
|
+
rare_label_value='positive'
|
|
4655
4714
|
)
|
|
4656
4715
|
```
|
|
4657
4716
|
|
|
@@ -4693,14 +4752,6 @@ class FeatrixSphereClient:
|
|
|
4693
4752
|
validation_ignore_columns: List of column names to exclude from validation queries (default: None)
|
|
4694
4753
|
rare_label_value: For binary classification, which class is the rare/minority class for metrics (default: None)
|
|
4695
4754
|
class_imbalance: Expected class ratios/counts from real world for sampled data (default: None)
|
|
4696
|
-
optimize_for: Optimization target - "balanced" (F1 score), "precision", or "recall" (default: "balanced").
|
|
4697
|
-
Ignored if cost_false_positive and cost_false_negative are provided.
|
|
4698
|
-
cost_false_positive: Cost of a false positive (predicting positive when actually negative).
|
|
4699
|
-
Must be specified together with cost_false_negative. Only valid for target_column_type="set".
|
|
4700
|
-
When provided, overrides optimize_for and uses cost-based optimization.
|
|
4701
|
-
cost_false_negative: Cost of a false negative (predicting negative when actually positive).
|
|
4702
|
-
Must be specified together with cost_false_positive. Only valid for target_column_type="set".
|
|
4703
|
-
When provided, overrides optimize_for and uses cost-based optimization.
|
|
4704
4755
|
poll_interval: Seconds between status checks when job is already running (default: 30)
|
|
4705
4756
|
max_poll_time: Maximum time to poll in seconds (default: 3600 = 1 hour)
|
|
4706
4757
|
verbose: Whether to print status updates during polling (default: True)
|
|
@@ -4727,7 +4778,6 @@ class FeatrixSphereClient:
|
|
|
4727
4778
|
raise ValueError("cost_false_positive and cost_false_negative must be positive numbers")
|
|
4728
4779
|
if verbose:
|
|
4729
4780
|
print(f"💰 Cost-based optimization enabled: FP cost={cost_false_positive}, FN cost={cost_false_negative}")
|
|
4730
|
-
print(f" (optimize_for='{optimize_for}' will be ignored)")
|
|
4731
4781
|
|
|
4732
4782
|
# If DataFrame provided, save to temp file and use file_path logic
|
|
4733
4783
|
temp_file = None
|
|
@@ -4761,7 +4811,6 @@ class FeatrixSphereClient:
|
|
|
4761
4811
|
epochs=epochs,
|
|
4762
4812
|
rare_label_value=rare_label_value,
|
|
4763
4813
|
class_imbalance=class_imbalance,
|
|
4764
|
-
optimize_for=optimize_for,
|
|
4765
4814
|
cost_false_positive=cost_false_positive,
|
|
4766
4815
|
cost_false_negative=cost_false_negative,
|
|
4767
4816
|
verbose=verbose,
|
|
@@ -4775,8 +4824,7 @@ class FeatrixSphereClient:
|
|
|
4775
4824
|
"epochs": epochs,
|
|
4776
4825
|
"validation_ignore_columns": validation_ignore_columns or [],
|
|
4777
4826
|
"rare_label_value": rare_label_value,
|
|
4778
|
-
"class_imbalance": class_imbalance
|
|
4779
|
-
"optimize_for": optimize_for
|
|
4827
|
+
"class_imbalance": class_imbalance
|
|
4780
4828
|
}
|
|
4781
4829
|
if cost_false_positive is not None and cost_false_negative is not None:
|
|
4782
4830
|
data["cost_false_positive"] = cost_false_positive
|
|
@@ -5353,7 +5401,6 @@ class FeatrixSphereClient:
|
|
|
5353
5401
|
epochs: int,
|
|
5354
5402
|
rare_label_value: str,
|
|
5355
5403
|
class_imbalance: dict,
|
|
5356
|
-
optimize_for: str,
|
|
5357
5404
|
cost_false_positive: float = None,
|
|
5358
5405
|
cost_false_negative: float = None,
|
|
5359
5406
|
verbose: bool = True,
|
|
@@ -5381,8 +5428,7 @@ class FeatrixSphereClient:
|
|
|
5381
5428
|
data = {
|
|
5382
5429
|
'target_column': target_column,
|
|
5383
5430
|
'target_column_type': target_column_type,
|
|
5384
|
-
'epochs': str(epochs)
|
|
5385
|
-
'optimize_for': optimize_for,
|
|
5431
|
+
'epochs': str(epochs)
|
|
5386
5432
|
}
|
|
5387
5433
|
|
|
5388
5434
|
if rare_label_value:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
featrixsphere/__init__.py,sha256=0gIgPqNrcFK35jlMQqSLQg9TqBwaiNU_PhZ4dQ3JOsw,1888
|
|
2
|
+
featrixsphere/cli.py,sha256=AW9O3vCvCNJ2UxVGN66eRmeN7XLSiHJlvK6JLZ9UJXc,13358
|
|
3
|
+
featrixsphere/client.py,sha256=NM-dBRANvN0GpcLf0BPqUxpqwMhzHP6hJktD8FndyCM,384646
|
|
4
|
+
featrixsphere/test_client.py,sha256=4SiRbib0ms3poK0UpnUv4G0HFQSzidF3Iswo_J2cjLk,11981
|
|
5
|
+
featrixsphere-0.2.1438.dist-info/METADATA,sha256=tNsudbOj5N1zFcjNA2iHZf6WJa4jxz1_MfhctYs8-qI,16232
|
|
6
|
+
featrixsphere-0.2.1438.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
featrixsphere-0.2.1438.dist-info/entry_points.txt,sha256=QreJeYfD_VWvbEqPmMXZ3pqqlFlJ1qZb-NtqnyhEldc,51
|
|
8
|
+
featrixsphere-0.2.1438.dist-info/top_level.txt,sha256=AyN4wjfzlD0hWnDieuEHX0KckphIk_aC73XCG4df5uU,14
|
|
9
|
+
featrixsphere-0.2.1438.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
featrixsphere/__init__.py,sha256=-zD2ZilYZFjYDB5rwnqr0jYNDB9zkO-hRgiD0LiXUGM,1888
|
|
2
|
-
featrixsphere/cli.py,sha256=AW9O3vCvCNJ2UxVGN66eRmeN7XLSiHJlvK6JLZ9UJXc,13358
|
|
3
|
-
featrixsphere/client.py,sha256=9GmwNP8Z4-HCQWEBDIXp54rbymRtJqwmBeQZZu5g27E,382816
|
|
4
|
-
featrixsphere/test_client.py,sha256=4SiRbib0ms3poK0UpnUv4G0HFQSzidF3Iswo_J2cjLk,11981
|
|
5
|
-
featrixsphere-0.2.1238.dist-info/METADATA,sha256=ILxoFLdu7zaEt1RzGAoCX_QGKMRCzv9hcB1zGr6_9FM,16232
|
|
6
|
-
featrixsphere-0.2.1238.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
featrixsphere-0.2.1238.dist-info/entry_points.txt,sha256=QreJeYfD_VWvbEqPmMXZ3pqqlFlJ1qZb-NtqnyhEldc,51
|
|
8
|
-
featrixsphere-0.2.1238.dist-info/top_level.txt,sha256=AyN4wjfzlD0hWnDieuEHX0KckphIk_aC73XCG4df5uU,14
|
|
9
|
-
featrixsphere-0.2.1238.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|