upgini 1.2.77__py3-none-any.whl → 1.2.78__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.
upgini/__about__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.2.77"
1
+ __version__ = "1.2.78"
@@ -757,7 +757,8 @@ class FeaturesEnricher(TransformerMixin):
757
757
  if new_progress:
758
758
  progress_bar.display()
759
759
  trace_id = trace_id or str(uuid.uuid4())
760
- with MDC(trace_id=trace_id):
760
+ search_id = self.search_id or (self._search_task.search_task_id if self._search_task is not None else None)
761
+ with MDC(trace_id=trace_id, search_id=search_id):
761
762
  self.dump_input(trace_id, X)
762
763
  if len(args) > 0:
763
764
  msg = f"WARNING: Unsupported positional arguments for transform: {args}"
@@ -887,7 +888,8 @@ class FeaturesEnricher(TransformerMixin):
887
888
 
888
889
  trace_id = trace_id or str(uuid.uuid4())
889
890
  start_time = time.time()
890
- with MDC(trace_id=trace_id):
891
+ search_id = self.search_id or (self._search_task.search_task_id if self._search_task is not None else None)
892
+ with MDC(trace_id=trace_id, search_id=search_id):
891
893
  self.logger.info("Start calculate metrics")
892
894
  if len(args) > 0:
893
895
  msg = f"WARNING: Unsupported positional arguments for calculate_metrics: {args}"
@@ -2199,7 +2201,8 @@ if response.status_code == 200:
2199
2201
  raise NotFittedError(self.bundle.get("transform_unfitted_enricher"))
2200
2202
 
2201
2203
  start_time = time.time()
2202
- with MDC(trace_id=trace_id):
2204
+ search_id = self.search_id or (self._search_task.search_task_id if self._search_task is not None else None)
2205
+ with MDC(trace_id=trace_id, search_id=search_id):
2203
2206
  self.logger.info("Start transform")
2204
2207
 
2205
2208
  validated_X = self._validate_X(X, is_transform=True)
@@ -2473,7 +2476,7 @@ if response.status_code == 200:
2473
2476
  gc.collect()
2474
2477
 
2475
2478
  if not silent_mode:
2476
- print(self.bundle.get("polling_search_task").format(validation_task.search_task_id))
2479
+ print(self.bundle.get("polling_transform_task").format(validation_task.search_task_id))
2477
2480
  if not self.__is_registered:
2478
2481
  print(self.bundle.get("polling_unregister_information"))
2479
2482
 
@@ -2989,137 +2992,141 @@ if response.status_code == 200:
2989
2992
  auto_fe_parameters=auto_fe_parameters,
2990
2993
  )
2991
2994
 
2992
- if search_id_callback is not None:
2993
- search_id_callback(self._search_task.search_task_id)
2995
+ with MDC(search_id=self._search_task.search_task_id):
2994
2996
 
2995
- print(self.bundle.get("polling_search_task").format(self._search_task.search_task_id))
2996
- if not self.__is_registered:
2997
- print(self.bundle.get("polling_unregister_information"))
2997
+ if search_id_callback is not None:
2998
+ search_id_callback(self._search_task.search_task_id)
2998
2999
 
2999
- progress = self.get_progress(trace_id)
3000
- prev_progress = None
3001
- progress.recalculate_eta(time.time() - start_time)
3002
- if progress_bar is not None:
3003
- progress_bar.progress = progress.to_progress_bar()
3004
- if progress_callback is not None:
3005
- progress_callback(progress)
3006
- poll_period_seconds = 1
3007
- try:
3008
- while progress.stage != ProgressStage.GENERATING_REPORT.value:
3009
- if prev_progress is None or prev_progress.percent != progress.percent:
3010
- progress.recalculate_eta(time.time() - start_time)
3011
- else:
3012
- progress.update_eta(prev_progress.eta - poll_period_seconds)
3013
- prev_progress = progress
3014
- if progress_bar is not None:
3015
- progress_bar.progress = progress.to_progress_bar()
3016
- if progress_callback is not None:
3017
- progress_callback(progress)
3018
- if progress.stage == ProgressStage.FAILED.value:
3019
- self.logger.error(
3020
- f"Search {self._search_task.search_task_id} failed with error {progress.error}"
3021
- f" and message {progress.error_message}"
3022
- )
3023
- raise RuntimeError(self.bundle.get("search_task_failed_status"))
3024
- time.sleep(poll_period_seconds)
3025
- progress = self.get_progress(trace_id)
3026
- except KeyboardInterrupt as e:
3027
- print(self.bundle.get("search_stopping"))
3028
- self.rest_client.stop_search_task_v2(trace_id, self._search_task.search_task_id)
3029
- self.logger.warning(f"Search {self._search_task.search_task_id} stopped by user")
3030
- print(self.bundle.get("search_stopped"))
3031
- raise e
3032
-
3033
- self._search_task.poll_result(trace_id, quiet=True)
3034
-
3035
- seconds_left = time.time() - start_time
3036
- progress = SearchProgress(97.0, ProgressStage.GENERATING_REPORT, seconds_left)
3037
- if progress_bar is not None:
3038
- progress_bar.progress = progress.to_progress_bar()
3039
- if progress_callback is not None:
3040
- progress_callback(progress)
3000
+ print(self.bundle.get("polling_search_task").format(self._search_task.search_task_id))
3001
+ if not self.__is_registered:
3002
+ print(self.bundle.get("polling_unregister_information"))
3041
3003
 
3042
- self.imbalanced = dataset.imbalanced
3004
+ progress = self.get_progress(trace_id)
3005
+ prev_progress = None
3006
+ progress.recalculate_eta(time.time() - start_time)
3007
+ if progress_bar is not None:
3008
+ progress_bar.progress = progress.to_progress_bar()
3009
+ if progress_callback is not None:
3010
+ progress_callback(progress)
3011
+ poll_period_seconds = 1
3012
+ try:
3013
+ while progress.stage != ProgressStage.GENERATING_REPORT.value:
3014
+ if prev_progress is None or prev_progress.percent != progress.percent:
3015
+ progress.recalculate_eta(time.time() - start_time)
3016
+ else:
3017
+ progress.update_eta(prev_progress.eta - poll_period_seconds)
3018
+ prev_progress = progress
3019
+ if progress_bar is not None:
3020
+ progress_bar.progress = progress.to_progress_bar()
3021
+ if progress_callback is not None:
3022
+ progress_callback(progress)
3023
+ if progress.stage == ProgressStage.FAILED.value:
3024
+ self.logger.error(
3025
+ f"Search {self._search_task.search_task_id} failed with error {progress.error}"
3026
+ f" and message {progress.error_message}"
3027
+ )
3028
+ raise RuntimeError(self.bundle.get("search_task_failed_status"))
3029
+ time.sleep(poll_period_seconds)
3030
+ progress = self.get_progress(trace_id)
3031
+ except KeyboardInterrupt as e:
3032
+ print(self.bundle.get("search_stopping"))
3033
+ self.rest_client.stop_search_task_v2(trace_id, self._search_task.search_task_id)
3034
+ self.logger.warning(f"Search {self._search_task.search_task_id} stopped by user")
3035
+ print(self.bundle.get("search_stopped"))
3036
+ raise e
3043
3037
 
3044
- zero_hit_search_keys = self._search_task.get_zero_hit_rate_search_keys()
3045
- if zero_hit_search_keys:
3046
- self.logger.warning(
3047
- f"Intersections with this search keys are empty for all datasets: {zero_hit_search_keys}"
3048
- )
3049
- zero_hit_columns = self.get_columns_by_search_keys(zero_hit_search_keys)
3050
- if zero_hit_columns:
3051
- msg = self.bundle.get("features_info_zero_hit_rate_search_keys").format(zero_hit_columns)
3052
- self.__log_warning(msg, show_support_link=True)
3038
+ self._search_task.poll_result(trace_id, quiet=True)
3053
3039
 
3054
- if (
3055
- self._search_task.unused_features_for_generation is not None
3056
- and len(self._search_task.unused_features_for_generation) > 0
3057
- ):
3058
- unused_features_for_generation = [
3059
- dataset.columns_renaming.get(col) or col for col in self._search_task.unused_features_for_generation
3060
- ]
3061
- msg = self.bundle.get("features_not_generated").format(unused_features_for_generation)
3062
- self.__log_warning(msg)
3040
+ seconds_left = time.time() - start_time
3041
+ progress = SearchProgress(97.0, ProgressStage.GENERATING_REPORT, seconds_left)
3042
+ if progress_bar is not None:
3043
+ progress_bar.progress = progress.to_progress_bar()
3044
+ if progress_callback is not None:
3045
+ progress_callback(progress)
3063
3046
 
3064
- self.__prepare_feature_importances(trace_id, df)
3047
+ self.imbalanced = dataset.imbalanced
3065
3048
 
3066
- self.__show_selected_features(self.fit_search_keys)
3049
+ zero_hit_search_keys = self._search_task.get_zero_hit_rate_search_keys()
3050
+ if zero_hit_search_keys:
3051
+ self.logger.warning(
3052
+ f"Intersections with this search keys are empty for all datasets: {zero_hit_search_keys}"
3053
+ )
3054
+ zero_hit_columns = self.get_columns_by_search_keys(zero_hit_search_keys)
3055
+ if zero_hit_columns:
3056
+ msg = self.bundle.get("features_info_zero_hit_rate_search_keys").format(zero_hit_columns)
3057
+ self.__log_warning(msg, show_support_link=True)
3067
3058
 
3068
- autofe_description = self.get_autofe_features_description()
3069
- if autofe_description is not None:
3070
- self.logger.info(f"AutoFE descriptions: {autofe_description}")
3071
- self.autofe_features_display_handle = display_html_dataframe(
3072
- df=autofe_description,
3073
- internal_df=autofe_description,
3074
- header=self.bundle.get("autofe_descriptions_header"),
3075
- display_id=f"autofe_descriptions_{uuid.uuid4()}",
3076
- )
3059
+ if (
3060
+ self._search_task.unused_features_for_generation is not None
3061
+ and len(self._search_task.unused_features_for_generation) > 0
3062
+ ):
3063
+ unused_features_for_generation = [
3064
+ dataset.columns_renaming.get(col) or col for col in self._search_task.unused_features_for_generation
3065
+ ]
3066
+ msg = self.bundle.get("features_not_generated").format(unused_features_for_generation)
3067
+ self.__log_warning(msg)
3077
3068
 
3078
- if self._has_paid_features(exclude_features_sources):
3079
- if calculate_metrics is not None and calculate_metrics:
3080
- msg = self.bundle.get("metrics_with_paid_features")
3081
- self.logger.warning(msg)
3082
- self.__display_support_link(msg)
3083
- else:
3084
- if (scoring is not None or estimator is not None) and calculate_metrics is None:
3085
- calculate_metrics = True
3069
+ self.__prepare_feature_importances(trace_id, df)
3086
3070
 
3087
- if calculate_metrics is None:
3088
- if len(validated_X) < self.CALCULATE_METRICS_MIN_THRESHOLD or any(
3089
- [len(eval_X) < self.CALCULATE_METRICS_MIN_THRESHOLD for eval_X, _ in validated_eval_set]
3090
- ):
3091
- msg = self.bundle.get("too_small_for_metrics")
3071
+ self.__show_selected_features(self.fit_search_keys)
3072
+
3073
+ autofe_description = self.get_autofe_features_description()
3074
+ if autofe_description is not None:
3075
+ self.logger.info(f"AutoFE descriptions: {autofe_description}")
3076
+ self.autofe_features_display_handle = display_html_dataframe(
3077
+ df=autofe_description,
3078
+ internal_df=autofe_description,
3079
+ header=self.bundle.get("autofe_descriptions_header"),
3080
+ display_id=f"autofe_descriptions_{uuid.uuid4()}",
3081
+ )
3082
+
3083
+ if self._has_paid_features(exclude_features_sources):
3084
+ if calculate_metrics is not None and calculate_metrics:
3085
+ msg = self.bundle.get("metrics_with_paid_features")
3092
3086
  self.logger.warning(msg)
3093
- calculate_metrics = False
3094
- elif len(dataset) * len(dataset.columns) > self.CALCULATE_METRICS_THRESHOLD:
3095
- self.logger.warning("Too big dataset for automatic metrics calculation")
3096
- calculate_metrics = False
3097
- else:
3087
+ self.__display_support_link(msg)
3088
+ else:
3089
+ if (scoring is not None or estimator is not None) and calculate_metrics is None:
3098
3090
  calculate_metrics = True
3099
3091
 
3100
- del df, validated_X, validated_y, dataset
3101
- gc.collect()
3092
+ if calculate_metrics is None:
3093
+ if len(validated_X) < self.CALCULATE_METRICS_MIN_THRESHOLD or any(
3094
+ [len(eval_X) < self.CALCULATE_METRICS_MIN_THRESHOLD for eval_X, _ in validated_eval_set]
3095
+ ):
3096
+ msg = self.bundle.get("too_small_for_metrics")
3097
+ self.logger.warning(msg)
3098
+ calculate_metrics = False
3099
+ elif len(dataset) * len(dataset.columns) > self.CALCULATE_METRICS_THRESHOLD:
3100
+ self.logger.warning("Too big dataset for automatic metrics calculation")
3101
+ calculate_metrics = False
3102
+ else:
3103
+ calculate_metrics = True
3102
3104
 
3103
- if calculate_metrics:
3104
- try:
3105
- self.__show_metrics(
3106
- scoring,
3107
- estimator,
3108
- importance_threshold,
3109
- max_features,
3110
- remove_outliers_calc_metrics,
3111
- trace_id,
3112
- progress_bar,
3113
- progress_callback,
3114
- )
3115
- except Exception:
3116
- self.report_button_handle = self.__show_report_button(display_id=f"report_button_{uuid.uuid4()}")
3117
- raise
3105
+ del df, validated_X, validated_y, dataset
3106
+ gc.collect()
3107
+
3108
+ if calculate_metrics:
3109
+ try:
3110
+ self.__show_metrics(
3111
+ scoring,
3112
+ estimator,
3113
+ importance_threshold,
3114
+ max_features,
3115
+ remove_outliers_calc_metrics,
3116
+ trace_id,
3117
+ progress_bar,
3118
+ progress_callback,
3119
+ )
3120
+ except Exception:
3121
+ self.report_button_handle = self.__show_report_button(
3122
+ display_id=f"report_button_{uuid.uuid4()}"
3123
+ )
3124
+ raise
3118
3125
 
3119
- self.report_button_handle = self.__show_report_button(display_id=f"report_button_{uuid.uuid4()}")
3126
+ self.report_button_handle = self.__show_report_button(display_id=f"report_button_{uuid.uuid4()}")
3120
3127
 
3121
- if not self.warning_counter.has_warnings():
3122
- self.__display_support_link(self.bundle.get("all_ok_community_invite"))
3128
+ if not self.warning_counter.has_warnings():
3129
+ self.__display_support_link(self.bundle.get("all_ok_community_invite"))
3123
3130
 
3124
3131
  def __should_add_date_column(self):
3125
3132
  return self.add_date_if_missing or (self.cv is not None and self.cv.is_time_series())
@@ -3443,7 +3450,8 @@ if response.status_code == 200:
3443
3450
  f"Estimator: {estimator}\n"
3444
3451
  f"Remove target outliers: {remove_outliers_calc_metrics}\n"
3445
3452
  f"Exclude columns: {self.exclude_columns}\n"
3446
- f"Search id: {self.search_id}\n"
3453
+ f"Passed search id: {self.search_id}\n"
3454
+ f"Search id from search task: {self._search_task.search_task_id if self._search_task else None}\n"
3447
3455
  f"Custom loss: {self.loss}\n"
3448
3456
  f"Logs enabled: {self.logs_enabled}\n"
3449
3457
  f"Raise validation error: {self.raise_validation_error}\n"
upgini/http.py CHANGED
@@ -125,6 +125,8 @@ class SearchTaskSummary:
125
125
  self.search_task_id = response["searchTaskId"]
126
126
  self.file_upload_id = response["fileUploadTaskId"]
127
127
  self.status = response["searchTaskStatus"]
128
+ self.task_type = response.get("searchTaskType")
129
+ self.initial_search_task_id = response.get("initialSearchTaskId")
128
130
  # self.features_found = response["featuresFoundCount"]
129
131
  # self.providers_checked = response["providersCheckedCount"]
130
132
  # self.important_providers_count = response["importantProvidersCount"]
@@ -7,6 +7,7 @@ transform_start=Retrieving selected features from data sources...
7
7
  search_stopping=Search interrupted. Stopping search request
8
8
  search_stopped=Search request stopped
9
9
  polling_search_task=\nRunning search request, search_id={}
10
+ polling_transform_task=\nRunning transform request, id={}
10
11
  polling_unregister_information=We'll send email notification once it's completed, just use your personal api_key from profile.upgini.com
11
12
  ads_upload_finish=Thank you for your submission!\nWe'll check your data sharing proposal and get back to you
12
13
  demo_dataset_info=Demo training dataset detected. Registration for an API key is not required.\n
@@ -67,6 +68,7 @@ unsupported_search_key=Search key {} not supported
67
68
  too_many_generate_features=Too many columns passed in `generate_features` argument. Only {} columns supported to generate features now
68
69
  invalid_round_embeddings=Argument `round_embeddings` should be non negative integer
69
70
  no_important_features_for_transform=There are no important features for transform. Return input as transformed
71
+ search_task_not_initial=Passed search_id {} is transform id. Please use search task id of fit call: {}.
70
72
 
71
73
  # Validation errors
72
74
  # params validation
upgini/search_task.py CHANGED
@@ -1,9 +1,9 @@
1
1
  import logging
2
2
  import tempfile
3
3
  import time
4
+ import uuid
4
5
  from functools import lru_cache
5
6
  from typing import Dict, List, Optional
6
- import uuid
7
7
 
8
8
  import pandas as pd
9
9
 
@@ -116,6 +116,11 @@ class SearchTask:
116
116
  self.logger.error(f"Search failed with errors: {','.join(error_messages)}")
117
117
  raise RuntimeError(bundle.get("all_providers_failed_with_error").format(",".join(error_messages)))
118
118
 
119
+ if check_fit and self.summary.task_type != "INITIAL":
120
+ raise RuntimeError(
121
+ bundle.get("search_task_not_initial").format(self.search_task_id, self.summary.initial_search_task_id)
122
+ )
123
+
119
124
  if self.summary.status in ["COMPLETED", "VALIDATION_COMPLETED"] or (
120
125
  check_fit and "VALIDATION" in self.summary.status
121
126
  ):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: upgini
3
- Version: 1.2.77
3
+ Version: 1.2.78
4
4
  Summary: Intelligent data search & enrichment for Machine Learning
5
5
  Project-URL: Bug Reports, https://github.com/upgini/upgini/issues
6
6
  Project-URL: Homepage, https://upgini.com/
@@ -1,13 +1,13 @@
1
- upgini/__about__.py,sha256=O1xqGt2rgTjvj07mjY1zhjZkS-9n0t1f6_sESHXFb5A,23
1
+ upgini/__about__.py,sha256=um-GnDBOmvXVFDzFeMIfwSF9jG0V0HqCNhYlIkfUoOQ,23
2
2
  upgini/__init__.py,sha256=LXSfTNU0HnlOkE69VCxkgIKDhWP-JFo_eBQ71OxTr5Y,261
3
3
  upgini/ads.py,sha256=nvuRxRx5MHDMgPr9SiU-fsqRdFaBv8p4_v1oqiysKpc,2714
4
4
  upgini/dataset.py,sha256=aspri7ZAgwkNNUiIgQ1GRXvw8XQii3F4RfNXSrF4wrw,35365
5
5
  upgini/errors.py,sha256=2b_Wbo0OYhLUbrZqdLIx5jBnAsiD1Mcenh-VjR4HCTw,950
6
- upgini/features_enricher.py,sha256=M_QxI7-yrDTXGpVEjMhjwR8yvIZh8Vxj9_63VaBZLWM,207132
7
- upgini/http.py,sha256=RvzcShpDXssLs6ycGN8xilkKi8ZV9XGUrrk8bwdUzbw,43607
6
+ upgini/features_enricher.py,sha256=_UkJS35uGaYtI7dR6Xd9Q28nmiPzTjhK3y8v3IjJTfQ,208245
7
+ upgini/http.py,sha256=UH7nswcZ221un3O_VW9limCBO5oRsyg1eKUHiVslRPs,43737
8
8
  upgini/metadata.py,sha256=Yd6iW2f7Wz6vUkg5uvR4xylN16ANnCKVKqAsAkap7p8,12354
9
9
  upgini/metrics.py,sha256=1AgIPEzd4sGJ8AlMrJziQruT-M1-lGgpnDIXUYeQJ6Q,39171
10
- upgini/search_task.py,sha256=EuCGp0iCWz2fpuJgN6M47aP_CtIi3Oq9zw78w0mkKiU,17595
10
+ upgini/search_task.py,sha256=RcvAE785yksWTsTNWuZFVNlk32jHElMoEna1T_C5N8Q,17823
11
11
  upgini/spinner.py,sha256=4iMd-eIe_BnkqFEMIliULTbj6rNI2HkN_VJ4qYe0cUc,1118
12
12
  upgini/version_validator.py,sha256=DvbaAvuYFoJqYt0fitpsk6Xcv-H1BYDJYHUMxaKSH_Y,1509
13
13
  upgini/ads_management/__init__.py,sha256=qzyisOToVRP-tquAJD1PblZhNtMrOB8FiyF9JvfkvgE,50
@@ -38,7 +38,7 @@ upgini/normalizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
38
38
  upgini/normalizer/normalize_utils.py,sha256=Ft2MwSgVoBilXAORAOYAuwPD79GOLfwn4qQE3IUFzzg,7218
39
39
  upgini/resource_bundle/__init__.py,sha256=S5F2G47pnJd2LDpmFsjDqEwiKkP8Hm-hcseDbMka6Ko,8345
40
40
  upgini/resource_bundle/exceptions.py,sha256=5fRvx0_vWdE1-7HcSgF0tckB4A9AKyf5RiinZkInTsI,621
41
- upgini/resource_bundle/strings.properties,sha256=mwQrerdJj3adzT-fHqvs6Qjf-rqDccsUzELDIXJKAmY,27791
41
+ upgini/resource_bundle/strings.properties,sha256=o9iLgAJSxXm6mkQgtNwBVQKIRVwLF1__Dn9gSXb1kLY,27953
42
42
  upgini/resource_bundle/strings_widget.properties,sha256=gOdqvZWntP2LCza_tyVk1_yRYcG4c04K9sQOAVhF_gw,1577
43
43
  upgini/sampler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  upgini/sampler/base.py,sha256=7GpjYqjOp58vYcJLiX__1R5wjUlyQbxvHJ2klFnup_M,6389
@@ -70,7 +70,7 @@ upgini/utils/target_utils.py,sha256=P0cCVRaakWLydYwFjk3TEaQfr0p0hfsJCvKRD8qcxiE,
70
70
  upgini/utils/track_info.py,sha256=G5Lu1xxakg2_TQjKZk4b5SvrHsATTXNVV3NbvWtT8k8,5663
71
71
  upgini/utils/ts_utils.py,sha256=26vhC0pN7vLXK6R09EEkMK3Lwb9IVPH7LRdqFIQ3kPs,1383
72
72
  upgini/utils/warning_counter.py,sha256=-GRY8EUggEBKODPSuXAkHn9KnEQwAORC0mmz_tim-PM,254
73
- upgini-1.2.77.dist-info/METADATA,sha256=75-l6Mbzg2HoUaocvJJO79ZL6rb54E42qmZ5Ucf88Cs,49091
74
- upgini-1.2.77.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
75
- upgini-1.2.77.dist-info/licenses/LICENSE,sha256=5RRzgvdJUu3BUDfv4bzVU6FqKgwHlIay63pPCSmSgzw,1514
76
- upgini-1.2.77.dist-info/RECORD,,
73
+ upgini-1.2.78.dist-info/METADATA,sha256=9NDKzhMak5vKoLrxoAAfTjU-HsTJByudWztn1gxxJyA,49091
74
+ upgini-1.2.78.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
75
+ upgini-1.2.78.dist-info/licenses/LICENSE,sha256=5RRzgvdJUu3BUDfv4bzVU6FqKgwHlIay63pPCSmSgzw,1514
76
+ upgini-1.2.78.dist-info/RECORD,,