Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/__init__.py +0 -0
- Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/instance.py +38 -0
- Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/metrics.py +578 -0
- Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/registry.py +196 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/accelerate-1.12.0.dist-info/licenses/LICENSE +201 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/_version.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__init__.py +12 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/_common.py +419 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/_factories.py +80 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/tz.py +1849 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/win.py +370 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__init__.py +167 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/__init__.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/config.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/hub.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/info.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/inspect.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/loading.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/module.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/naming.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/saving.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/visualization.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__init__.py +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__pycache__/__init__.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__pycache__/evaluate_cli.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/evaluate_cli.py +137 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluation_suite/__pycache__/__init__.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__init__.py +140 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/audio_classification.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/automatic_speech_recognition.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/base.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/image_classification.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/question_answering.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text2text_generation.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text_classification.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text_generation.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/token_classification.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/audio_classification.py +151 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/automatic_speech_recognition.py +112 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/base.py +544 -0
- Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/image_classification.py +119 -0
Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/__init__.py
ADDED
|
File without changes
|
Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/instance.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass, field
|
| 2 |
+
from typing import Literal, Optional, Tuple
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
OutputType = Literal[
|
| 6 |
+
"loglikelihood", "loglikelihood_rolling", "generate_until", "multiple_choice"
|
| 7 |
+
]
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@dataclass
|
| 11 |
+
class Instance:
|
| 12 |
+
request_type: OutputType
|
| 13 |
+
doc: dict
|
| 14 |
+
arguments: tuple
|
| 15 |
+
idx: int
|
| 16 |
+
metadata: Tuple[Optional[str], Optional[int], Optional[int]] = field(
|
| 17 |
+
default_factory=lambda: (None, None, None)
|
| 18 |
+
)
|
| 19 |
+
resps: list = field(default_factory=list)
|
| 20 |
+
filtered_resps: dict = field(default_factory=dict)
|
| 21 |
+
|
| 22 |
+
# initialized after init
|
| 23 |
+
task_name: Optional[str] = None
|
| 24 |
+
doc_id: Optional[int] = None
|
| 25 |
+
repeats: Optional[int] = None
|
| 26 |
+
|
| 27 |
+
def __post_init__(self) -> None:
|
| 28 |
+
# unpack metadata field
|
| 29 |
+
self.task_name, self.doc_id, self.repeats = self.metadata
|
| 30 |
+
|
| 31 |
+
@property
|
| 32 |
+
def args(self):
|
| 33 |
+
"""
|
| 34 |
+
Returns (string,) where `string` is the string to calculate loglikelihood over
|
| 35 |
+
"""
|
| 36 |
+
return (
|
| 37 |
+
self.arguments if isinstance(self.arguments, tuple) else (self.arguments,)
|
| 38 |
+
)
|
Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/metrics.py
ADDED
|
@@ -0,0 +1,578 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import math
|
| 3 |
+
import random
|
| 4 |
+
import re
|
| 5 |
+
import string
|
| 6 |
+
from collections.abc import Iterable
|
| 7 |
+
from typing import List
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import sacrebleu
|
| 11 |
+
|
| 12 |
+
from lm_eval.api.registry import register_aggregation, register_metric
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
eval_logger = logging.getLogger(__name__)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# Register Aggregations First
|
| 19 |
+
@register_aggregation("bypass")
|
| 20 |
+
def bypass_agg(arr):
|
| 21 |
+
return 999
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@register_aggregation("nanmean")
|
| 25 |
+
def nanmean(arr):
|
| 26 |
+
if len(arr) == 0 or all(np.isnan(arr)):
|
| 27 |
+
return np.nan
|
| 28 |
+
return np.nanmean(arr)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@register_aggregation("mean")
|
| 32 |
+
def mean(arr):
|
| 33 |
+
return sum(arr) / len(arr)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
@register_aggregation("median")
|
| 37 |
+
def median(arr):
|
| 38 |
+
return arr[len(arr) // 2]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# Certain metrics must be calculated across all documents in a benchmark.
|
| 42 |
+
# We use them as aggregation metrics, paired with no-op passthrough metric fns.
|
| 43 |
+
@register_aggregation("perplexity")
|
| 44 |
+
def perplexity(items):
|
| 45 |
+
return math.exp(-mean(items))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@register_aggregation("weighted_perplexity")
|
| 49 |
+
def weighted_perplexity(items):
|
| 50 |
+
return math.exp(-weighted_mean(items))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@register_aggregation("bits_per_byte")
|
| 54 |
+
def bits_per_byte(items):
|
| 55 |
+
return -weighted_mean(items) / math.log(2)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
@register_aggregation("f1")
|
| 59 |
+
def f1_score(items):
|
| 60 |
+
from sklearn.metrics import f1_score
|
| 61 |
+
|
| 62 |
+
unzipped_list = list(zip(*items))
|
| 63 |
+
golds = unzipped_list[0]
|
| 64 |
+
preds = unzipped_list[1]
|
| 65 |
+
fscore = f1_score(golds, preds)
|
| 66 |
+
|
| 67 |
+
return np.max(fscore)
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
@register_aggregation("matthews_corrcoef")
|
| 71 |
+
def matthews_corrcoef(items):
|
| 72 |
+
from sklearn.metrics import matthews_corrcoef
|
| 73 |
+
|
| 74 |
+
unzipped_list = list(zip(*items))
|
| 75 |
+
golds = unzipped_list[0]
|
| 76 |
+
preds = unzipped_list[1]
|
| 77 |
+
return matthews_corrcoef(golds, preds)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
@register_aggregation("bleu")
|
| 81 |
+
def bleu(items):
|
| 82 |
+
"""The Bilingual Evaluation Understudy Score, or BLEU for short, is a metric
|
| 83 |
+
for evaluating a generated sentence to a reference sentence. It counts matching
|
| 84 |
+
n-grams in the candidate translation to n-grams in the reference text, where
|
| 85 |
+
1-gram or unigram would be each token and a bigram comparison would be each
|
| 86 |
+
word pair. The comparison is made regardless of word order
|
| 87 |
+
Source: https://machinelearningmastery.com/calculate-bleu-score-for-text-python/
|
| 88 |
+
Paper: https://www.aclweb.org/anthology/P02-1040/
|
| 89 |
+
|
| 90 |
+
Higher is better
|
| 91 |
+
"""
|
| 92 |
+
refs = list(zip(*items))[0]
|
| 93 |
+
preds = list(zip(*items))[1]
|
| 94 |
+
refs, preds = _sacreformat(refs, preds)
|
| 95 |
+
return sacrebleu.corpus_bleu(preds, refs).score
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
@register_aggregation("chrf")
|
| 99 |
+
def chrf(items):
|
| 100 |
+
"""chrF++ is a tool for automatic evaluation of machine translation output
|
| 101 |
+
based on character n-gram precision and recall enhanced with word n-grams.
|
| 102 |
+
Source: https://github.com/m-popovic/chrF
|
| 103 |
+
Paper: https://www.aclweb.org/anthology/W15-3049.pdf
|
| 104 |
+
|
| 105 |
+
Higher is better # TODO I think
|
| 106 |
+
"""
|
| 107 |
+
refs = list(zip(*items))[0]
|
| 108 |
+
preds = list(zip(*items))[1]
|
| 109 |
+
refs, preds = _sacreformat(refs, preds)
|
| 110 |
+
return sacrebleu.corpus_chrf(preds, refs).score
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
@register_aggregation("ter")
|
| 114 |
+
def ter(items):
|
| 115 |
+
"""Translation Error Rate is an error metric for machine translation that
|
| 116 |
+
measures the number of edits required to change a system output into one
|
| 117 |
+
of the references
|
| 118 |
+
Source: http://www.cs.umd.edu/~snover/tercom/
|
| 119 |
+
Paper: http://mt-archive.info/AMTA-2006-Snover.pdf
|
| 120 |
+
|
| 121 |
+
Lower is better
|
| 122 |
+
"""
|
| 123 |
+
refs = list(zip(*items))[0]
|
| 124 |
+
preds = list(zip(*items))[1]
|
| 125 |
+
refs, preds = _sacreformat(refs, preds)
|
| 126 |
+
return sacrebleu.corpus_ter(preds, refs).score
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
@register_aggregation("brier_score")
|
| 130 |
+
def brier_score(items): # This is a passthrough function
|
| 131 |
+
gold, predictions = list(zip(*items))
|
| 132 |
+
bs, num_class = np.array(predictions).shape
|
| 133 |
+
|
| 134 |
+
gold = list(gold)
|
| 135 |
+
gold_one_hot = np.eye(num_class)[gold]
|
| 136 |
+
return np.mean(np.sum((predictions - gold_one_hot) ** 2, axis=1))
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
@register_metric(
|
| 140 |
+
metric="brier_score",
|
| 141 |
+
higher_is_better=False,
|
| 142 |
+
output_type=["multiple_choice"],
|
| 143 |
+
aggregation="brier_score",
|
| 144 |
+
)
|
| 145 |
+
def brier_score_fn(items): # This is a passthrough function
|
| 146 |
+
return items
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@register_metric(
|
| 150 |
+
metric="acc",
|
| 151 |
+
higher_is_better=True,
|
| 152 |
+
output_type=["loglikelihood", "multiple_choice"],
|
| 153 |
+
aggregation="mean",
|
| 154 |
+
)
|
| 155 |
+
def acc_fn(items): # This is a passthrough function
|
| 156 |
+
return items
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
@register_metric(
|
| 160 |
+
metric="acc_norm",
|
| 161 |
+
higher_is_better=True,
|
| 162 |
+
output_type=["loglikelihood", "multiple_choice"],
|
| 163 |
+
aggregation="mean",
|
| 164 |
+
)
|
| 165 |
+
def acc_norm_fn(items): # This is a passthrough function
|
| 166 |
+
return items
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
@register_metric(
|
| 170 |
+
metric="acc_mutual_info",
|
| 171 |
+
higher_is_better=True,
|
| 172 |
+
output_type="multiple_choice",
|
| 173 |
+
aggregation="mean",
|
| 174 |
+
)
|
| 175 |
+
def acc_mutual_info_fn(items): # This is a passthrough function
|
| 176 |
+
return items
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
### the code used in the `exact_match_hf_evaluate` function is ported from
|
| 180 |
+
### https://github.com/huggingface/evaluate/blob/main/metrics/exact_match/exact_match.py
|
| 181 |
+
### which is under the apache license.
|
| 182 |
+
|
| 183 |
+
# Copyright 2020 The HuggingFace Datasets Authors and the current dataset script contributor.
|
| 184 |
+
|
| 185 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 186 |
+
# you may not use this file except in compliance with the License.
|
| 187 |
+
# You may obtain a copy of the License at
|
| 188 |
+
|
| 189 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 193 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 194 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 195 |
+
# See the License for the specific language governing permissions and
|
| 196 |
+
# limitations under the License.
|
| 197 |
+
def exact_match_hf_evaluate(
|
| 198 |
+
predictions,
|
| 199 |
+
references,
|
| 200 |
+
regexes_to_ignore=None,
|
| 201 |
+
ignore_case=False,
|
| 202 |
+
ignore_punctuation=False,
|
| 203 |
+
ignore_numbers=False,
|
| 204 |
+
):
|
| 205 |
+
if regexes_to_ignore is not None:
|
| 206 |
+
for s in regexes_to_ignore:
|
| 207 |
+
predictions = np.array([re.sub(s, "", x) for x in predictions])
|
| 208 |
+
references = np.array([re.sub(s, "", x) for x in references])
|
| 209 |
+
else:
|
| 210 |
+
predictions = np.asarray(predictions)
|
| 211 |
+
references = np.asarray(references)
|
| 212 |
+
|
| 213 |
+
if ignore_case:
|
| 214 |
+
predictions = np.char.lower(predictions)
|
| 215 |
+
references = np.char.lower(references)
|
| 216 |
+
|
| 217 |
+
if ignore_punctuation:
|
| 218 |
+
repl_table = string.punctuation.maketrans("", "", string.punctuation)
|
| 219 |
+
predictions = np.char.translate(predictions, table=repl_table)
|
| 220 |
+
references = np.char.translate(references, table=repl_table)
|
| 221 |
+
|
| 222 |
+
if ignore_numbers:
|
| 223 |
+
repl_table = string.digits.maketrans("", "", string.digits)
|
| 224 |
+
predictions = np.char.translate(predictions, table=repl_table)
|
| 225 |
+
references = np.char.translate(references, table=repl_table)
|
| 226 |
+
|
| 227 |
+
score_list = predictions == references
|
| 228 |
+
|
| 229 |
+
return {"exact_match": np.mean(score_list)}
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
###
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
@register_metric(
|
| 236 |
+
metric="exact_match",
|
| 237 |
+
higher_is_better=True,
|
| 238 |
+
output_type="generate_until",
|
| 239 |
+
aggregation="mean",
|
| 240 |
+
)
|
| 241 |
+
def exact_match_fn(**kwargs):
|
| 242 |
+
return exact_match_hf_evaluate(**kwargs)
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
@register_metric(
|
| 246 |
+
metric="perplexity",
|
| 247 |
+
higher_is_better=False,
|
| 248 |
+
output_type="loglikelihood",
|
| 249 |
+
aggregation="perplexity",
|
| 250 |
+
)
|
| 251 |
+
def perplexity_fn(items): # This is a passthrough function
|
| 252 |
+
return items
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
@register_metric(
|
| 256 |
+
metric="word_perplexity",
|
| 257 |
+
higher_is_better=False,
|
| 258 |
+
output_type="loglikelihood_rolling",
|
| 259 |
+
aggregation="weighted_perplexity",
|
| 260 |
+
)
|
| 261 |
+
def word_perplexity_fn(items): # This is a passthrough function
|
| 262 |
+
return items
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
@register_metric(
|
| 266 |
+
metric="byte_perplexity",
|
| 267 |
+
higher_is_better=False,
|
| 268 |
+
output_type="loglikelihood_rolling",
|
| 269 |
+
aggregation="weighted_perplexity",
|
| 270 |
+
)
|
| 271 |
+
def byte_perplexity_fn(items): # This is a passthrough function
|
| 272 |
+
return items
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
@register_metric(
|
| 276 |
+
metric="bits_per_byte",
|
| 277 |
+
higher_is_better=False,
|
| 278 |
+
output_type="loglikelihood_rolling",
|
| 279 |
+
aggregation="bits_per_byte",
|
| 280 |
+
)
|
| 281 |
+
def bits_per_byte_fn(items): # This is a passthrough function
|
| 282 |
+
return items
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
def pop_stddev(arr):
|
| 286 |
+
mu = mean(arr)
|
| 287 |
+
return math.sqrt(sum([(x - mu) ** 2 for x in arr]) / len(arr))
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def sample_stddev(arr):
|
| 291 |
+
mu = mean(arr)
|
| 292 |
+
return math.sqrt(sum([(x - mu) ** 2 for x in arr]) / (len(arr) - 1))
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
def mean_stderr(arr):
|
| 296 |
+
return sample_stddev(arr) / math.sqrt(len(arr))
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
@register_metric(
|
| 300 |
+
metric="bypass",
|
| 301 |
+
higher_is_better=True,
|
| 302 |
+
output_type=["loglikelihood", "multiple_choice", "generate_until"],
|
| 303 |
+
aggregation="bypass",
|
| 304 |
+
)
|
| 305 |
+
def bypass(items):
|
| 306 |
+
return None
|
| 307 |
+
|
| 308 |
+
|
| 309 |
+
@register_metric(
|
| 310 |
+
metric="mcc",
|
| 311 |
+
higher_is_better=True,
|
| 312 |
+
output_type="multiple_choice",
|
| 313 |
+
aggregation="matthews_corrcoef",
|
| 314 |
+
)
|
| 315 |
+
def mcc_fn(items): # This is a passthrough function
|
| 316 |
+
return items
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
@register_metric(
|
| 320 |
+
metric="f1",
|
| 321 |
+
higher_is_better=True,
|
| 322 |
+
output_type="multiple_choice",
|
| 323 |
+
aggregation="f1",
|
| 324 |
+
)
|
| 325 |
+
def f1_fn(items): # This is a passthrough function
|
| 326 |
+
return items
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
@register_metric(
|
| 330 |
+
metric="bleu",
|
| 331 |
+
higher_is_better=True,
|
| 332 |
+
output_type="generate_until",
|
| 333 |
+
aggregation="bleu",
|
| 334 |
+
)
|
| 335 |
+
def bleu_fn(items): # This is a passthrough function
|
| 336 |
+
return items
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
@register_metric(
|
| 340 |
+
metric="chrf",
|
| 341 |
+
higher_is_better=True,
|
| 342 |
+
output_type="generate_until",
|
| 343 |
+
aggregation="chrf",
|
| 344 |
+
)
|
| 345 |
+
def chrf_fn(items): # This is a passthrough function
|
| 346 |
+
return items
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
@register_metric(
|
| 350 |
+
metric="ter",
|
| 351 |
+
higher_is_better=True,
|
| 352 |
+
output_type="generate_until",
|
| 353 |
+
aggregation="ter",
|
| 354 |
+
)
|
| 355 |
+
def ter_fn(items): # This is a passthrough function
|
| 356 |
+
return items
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
@register_metric(
|
| 360 |
+
metric="acc_all",
|
| 361 |
+
higher_is_better=True,
|
| 362 |
+
output_type="loglikelihood",
|
| 363 |
+
aggregation="mean",
|
| 364 |
+
)
|
| 365 |
+
def acc_all(items):
|
| 366 |
+
# Only count as correct if all answers are labeled correctly for each question
|
| 367 |
+
question_scoring_dict = {}
|
| 368 |
+
preds = list(zip(*items))[0]
|
| 369 |
+
docs = list(zip(*items))[1]
|
| 370 |
+
|
| 371 |
+
for doc, pred in zip(docs, preds):
|
| 372 |
+
paragraph_id = doc["idx"]["paragraph"]
|
| 373 |
+
question_id = doc["idx"]["question"]
|
| 374 |
+
if (paragraph_id, question_id) not in question_scoring_dict:
|
| 375 |
+
question_scoring_dict[(paragraph_id, question_id)] = []
|
| 376 |
+
|
| 377 |
+
gold_label = doc["label"] == 1
|
| 378 |
+
|
| 379 |
+
question_scoring_dict[(paragraph_id, question_id)].append(gold_label == pred)
|
| 380 |
+
acc = np.mean([int(all(x)) for x in question_scoring_dict.values()])
|
| 381 |
+
return acc
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
def acc_all_stderr(items):
|
| 385 |
+
# Only count as correct if all answers are labeled correctly for each question
|
| 386 |
+
question_scoring_dict = {}
|
| 387 |
+
preds = list(zip(*items))[0]
|
| 388 |
+
docs = list(zip(*items))[1]
|
| 389 |
+
|
| 390 |
+
for doc, pred in zip(docs, preds):
|
| 391 |
+
question_id = doc["idx"]["question"]
|
| 392 |
+
if question_id not in question_scoring_dict:
|
| 393 |
+
question_scoring_dict[question_id] = []
|
| 394 |
+
|
| 395 |
+
gold_label = doc["label"] == 1
|
| 396 |
+
question_scoring_dict[question_id].append(gold_label == pred)
|
| 397 |
+
|
| 398 |
+
acc = mean_stderr([int(all(x)) for x in question_scoring_dict.values()])
|
| 399 |
+
return acc
|
| 400 |
+
|
| 401 |
+
|
| 402 |
+
def metric_max_over_ground_truths(metric_fn, prediction, ground_truths):
|
| 403 |
+
"""Compute max metric between prediction and each ground truth."""
|
| 404 |
+
scores_for_ground_truths = []
|
| 405 |
+
for ground_truth in ground_truths:
|
| 406 |
+
score = metric_fn(prediction, ground_truth)
|
| 407 |
+
scores_for_ground_truths.append(score)
|
| 408 |
+
return max(scores_for_ground_truths)
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
def weighted_mean(items):
|
| 412 |
+
a, b = zip(*items)
|
| 413 |
+
return sum(a) / sum(b)
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
def is_non_str_iterable(obj):
|
| 417 |
+
return isinstance(obj, Iterable) and not isinstance(obj, str)
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def _sacreformat(refs, preds):
|
| 421 |
+
"""Format refs and preds for sacrebleu corpus calculation. It is very particular"""
|
| 422 |
+
# Sacrebleu expects (List[str], List[List[str])
|
| 423 |
+
# e.g. sacrebleu.corpus_bleu([pred_t], [[ref1_stream], [ref2_stream], ...])
|
| 424 |
+
|
| 425 |
+
# Note [ref1_stream] is the first reference for each pred.
|
| 426 |
+
# So lists are size N and (M, N) for N preds and M possible refs for each pred
|
| 427 |
+
# This is a different order of dimensions that I would expect
|
| 428 |
+
|
| 429 |
+
# We expect refs to be List[str] or List[List[str]], the outer list corresponding to preds
|
| 430 |
+
# Must become List[List[str]] with the inner list corresponding to preds
|
| 431 |
+
if not is_non_str_iterable(refs):
|
| 432 |
+
refs = list(refs)
|
| 433 |
+
if not is_non_str_iterable(refs[0]):
|
| 434 |
+
refs = [[ref] for ref in refs]
|
| 435 |
+
refs = list(zip(*refs))
|
| 436 |
+
# Note the number of refs in each ref list much match the number of preds
|
| 437 |
+
|
| 438 |
+
# We expect preds to be List[str] or List[List[str]]. Must become List[str]
|
| 439 |
+
if not is_non_str_iterable(preds):
|
| 440 |
+
preds = list(preds)
|
| 441 |
+
if is_non_str_iterable(preds[0]):
|
| 442 |
+
assert len(preds[0]) == 1, f"Pred must be a str, was {preds[0]}"
|
| 443 |
+
preds = [pred[0] for pred in preds]
|
| 444 |
+
|
| 445 |
+
return refs, preds
|
| 446 |
+
|
| 447 |
+
|
| 448 |
+
# stderr stuff
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
class _bootstrap_internal:
|
| 452 |
+
def __init__(self, f, n) -> None:
|
| 453 |
+
self.f = f
|
| 454 |
+
self.n = n
|
| 455 |
+
|
| 456 |
+
def __call__(self, v):
|
| 457 |
+
i, xs = v
|
| 458 |
+
rnd = random.Random()
|
| 459 |
+
rnd.seed(i)
|
| 460 |
+
res = []
|
| 461 |
+
for _ in range(self.n):
|
| 462 |
+
res.append(self.f(rnd.choices(xs, k=len(xs))))
|
| 463 |
+
return res
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def bootstrap_stderr(f, xs, iters):
|
| 467 |
+
import multiprocessing as mp
|
| 468 |
+
|
| 469 |
+
pool = mp.Pool(mp.cpu_count())
|
| 470 |
+
# this gives a biased estimate of the stderr (i.e w/ the mean, it gives something
|
| 471 |
+
# equivalent to stderr calculated without Bessel's correction in the stddev.
|
| 472 |
+
# Unfortunately, I haven't been able to figure out what the right correction is
|
| 473 |
+
# to make the bootstrap unbiased - i considered multiplying by sqrt(n/(n-1)) but
|
| 474 |
+
# that would be ad-hoc and I can't prove that that would actually be an unbiased estimator)
|
| 475 |
+
# Thankfully, shouldn't matter because our samples are pretty big usually anyways
|
| 476 |
+
res = []
|
| 477 |
+
chunk_size = min(1000, iters)
|
| 478 |
+
from tqdm import tqdm
|
| 479 |
+
|
| 480 |
+
print("bootstrapping for stddev:", f.__name__)
|
| 481 |
+
for bootstrap in tqdm(
|
| 482 |
+
pool.imap(
|
| 483 |
+
_bootstrap_internal(f, chunk_size),
|
| 484 |
+
[(i, xs) for i in range(iters // chunk_size)],
|
| 485 |
+
),
|
| 486 |
+
total=iters // chunk_size,
|
| 487 |
+
):
|
| 488 |
+
# sample w replacement
|
| 489 |
+
res.extend(bootstrap)
|
| 490 |
+
|
| 491 |
+
pool.close()
|
| 492 |
+
return sample_stddev(res)
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def stderr_for_metric(metric, bootstrap_iters: int):
|
| 496 |
+
if bootstrap_iters <= 0:
|
| 497 |
+
# return no function (don't compute stderr) if bootstrap iters = 0
|
| 498 |
+
return None
|
| 499 |
+
|
| 500 |
+
bootstrappable = [
|
| 501 |
+
median,
|
| 502 |
+
matthews_corrcoef,
|
| 503 |
+
f1_score,
|
| 504 |
+
perplexity,
|
| 505 |
+
bleu,
|
| 506 |
+
chrf,
|
| 507 |
+
ter,
|
| 508 |
+
nanmean,
|
| 509 |
+
]
|
| 510 |
+
|
| 511 |
+
if metric in bootstrappable:
|
| 512 |
+
return lambda x: bootstrap_stderr(metric, x, iters=bootstrap_iters)
|
| 513 |
+
|
| 514 |
+
stderr = {mean: mean_stderr, acc_all: acc_all_stderr}
|
| 515 |
+
|
| 516 |
+
return stderr.get(metric, None)
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
def pooled_sample_stderr(stderrs: List[float], sizes: List[int]):
|
| 520 |
+
# Used to aggregate bootstrapped stderrs across subtasks in a group,
|
| 521 |
+
# when we are weighting by the size of each subtask.
|
| 522 |
+
#
|
| 523 |
+
|
| 524 |
+
assert len(stderrs) == len(sizes)
|
| 525 |
+
|
| 526 |
+
# formula source: https://en.wikipedia.org/wiki/Pooled_variance
|
| 527 |
+
# and: https://stats.stackexchange.com/a/4841331
|
| 528 |
+
# this empirically seems to match running `stderr_for_metric` on all instances
|
| 529 |
+
# from the subtasks concatenated with each other.
|
| 530 |
+
pooled_sample_var = (
|
| 531 |
+
sum([(size - 1) * stderr**2 * size for size, stderr in zip(sizes, stderrs)])
|
| 532 |
+
) / (sum(sizes) - len(sizes))
|
| 533 |
+
|
| 534 |
+
return np.sqrt(pooled_sample_var / sum(sizes))
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
def combined_sample_stderr(stderrs: List[float], sizes: List[int], metrics=None):
|
| 538 |
+
assert metrics is not None, (
|
| 539 |
+
"Need to pass a list of each subtask's metric for this stderr aggregation"
|
| 540 |
+
)
|
| 541 |
+
assert len(stderrs) == len(sizes) and len(sizes) == len(metrics)
|
| 542 |
+
|
| 543 |
+
# See https://github.com/EleutherAI/lm-evaluation-harness/pull/1390 for more documentation.
|
| 544 |
+
# This formula depends on sample means.
|
| 545 |
+
# removed because it seems to give erroneously huge stderrs for groupings of tasks
|
| 546 |
+
# and does not seem to match up with bootstrap-calculated stderrs for groups.
|
| 547 |
+
|
| 548 |
+
### don't use this unless a statistician has told you it's the right thing to do ###
|
| 549 |
+
|
| 550 |
+
# accumulators: we'll aggregate pairwise N - 1 times
|
| 551 |
+
variance = stderrs[0] ** 2
|
| 552 |
+
curr_size = sizes[0]
|
| 553 |
+
curr_score = metrics[0]
|
| 554 |
+
|
| 555 |
+
for stderr, size, score in zip(stderrs[1:], sizes[1:], metrics[1:]):
|
| 556 |
+
curr_score = ((curr_score * curr_size) + (score * size)) / (
|
| 557 |
+
curr_size + size
|
| 558 |
+
) # NOTE: this assumes our aggregation fn is "mean"
|
| 559 |
+
|
| 560 |
+
variance = ((curr_size - 1) * variance + (size - 1) * (stderr**2)) / (
|
| 561 |
+
curr_size + size - 1
|
| 562 |
+
) + curr_size * size / ((curr_size + size) * (curr_size + size - 1)) * (
|
| 563 |
+
curr_score - score
|
| 564 |
+
) ** 2
|
| 565 |
+
|
| 566 |
+
return np.sqrt(variance)
|
| 567 |
+
|
| 568 |
+
|
| 569 |
+
def aggregate_subtask_metrics(metrics, sizes, weight_by_size=True):
|
| 570 |
+
# A helper function that is used to aggregate
|
| 571 |
+
# subtask scores cross-task.
|
| 572 |
+
# TODO: does not hold for non-mean aggregations
|
| 573 |
+
if not weight_by_size:
|
| 574 |
+
sizes = [1] * len(sizes)
|
| 575 |
+
|
| 576 |
+
assert len(metrics) == len(sizes)
|
| 577 |
+
|
| 578 |
+
return sum([metric * size for metric, size in zip(metrics, sizes)]) / sum(sizes)
|
Prism/Dream/Dream_Prism/eval_instruct/lm_eval/api/registry.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from typing import Callable, Dict, Union
|
| 3 |
+
|
| 4 |
+
import evaluate as hf_evaluate
|
| 5 |
+
|
| 6 |
+
from lm_eval.api.model import LM
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
eval_logger = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
MODEL_REGISTRY = {}
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def register_model(*names):
|
| 15 |
+
# either pass a list or a single alias.
|
| 16 |
+
# function receives them as a tuple of strings
|
| 17 |
+
|
| 18 |
+
def decorate(cls):
|
| 19 |
+
for name in names:
|
| 20 |
+
assert issubclass(cls, LM), (
|
| 21 |
+
f"Model '{name}' ({cls.__name__}) must extend LM class"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
assert name not in MODEL_REGISTRY, (
|
| 25 |
+
f"Model named '{name}' conflicts with existing model! Please register with a non-conflicting alias instead."
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
MODEL_REGISTRY[name] = cls
|
| 29 |
+
return cls
|
| 30 |
+
|
| 31 |
+
return decorate
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def get_model(model_name):
|
| 35 |
+
try:
|
| 36 |
+
return MODEL_REGISTRY[model_name]
|
| 37 |
+
except KeyError:
|
| 38 |
+
raise ValueError(
|
| 39 |
+
f"Attempted to load model '{model_name}', but no model for this name found! Supported model names: {', '.join(MODEL_REGISTRY.keys())}"
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
TASK_REGISTRY = {}
|
| 44 |
+
GROUP_REGISTRY = {}
|
| 45 |
+
ALL_TASKS = set()
|
| 46 |
+
func2task_index = {}
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def register_task(name):
|
| 50 |
+
def decorate(fn):
|
| 51 |
+
assert name not in TASK_REGISTRY, (
|
| 52 |
+
f"task named '{name}' conflicts with existing registered task!"
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
TASK_REGISTRY[name] = fn
|
| 56 |
+
ALL_TASKS.add(name)
|
| 57 |
+
func2task_index[fn.__name__] = name
|
| 58 |
+
return fn
|
| 59 |
+
|
| 60 |
+
return decorate
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def register_group(name):
|
| 64 |
+
def decorate(fn):
|
| 65 |
+
func_name = func2task_index[fn.__name__]
|
| 66 |
+
if name in GROUP_REGISTRY:
|
| 67 |
+
GROUP_REGISTRY[name].append(func_name)
|
| 68 |
+
else:
|
| 69 |
+
GROUP_REGISTRY[name] = [func_name]
|
| 70 |
+
ALL_TASKS.add(name)
|
| 71 |
+
return fn
|
| 72 |
+
|
| 73 |
+
return decorate
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
OUTPUT_TYPE_REGISTRY = {}
|
| 77 |
+
METRIC_REGISTRY = {}
|
| 78 |
+
METRIC_AGGREGATION_REGISTRY = {}
|
| 79 |
+
AGGREGATION_REGISTRY: Dict[str, Callable[[], Dict[str, Callable]]] = {}
|
| 80 |
+
HIGHER_IS_BETTER_REGISTRY = {}
|
| 81 |
+
FILTER_REGISTRY = {}
|
| 82 |
+
|
| 83 |
+
DEFAULT_METRIC_REGISTRY = {
|
| 84 |
+
"loglikelihood": [
|
| 85 |
+
"perplexity",
|
| 86 |
+
"acc",
|
| 87 |
+
],
|
| 88 |
+
"loglikelihood_rolling": ["word_perplexity", "byte_perplexity", "bits_per_byte"],
|
| 89 |
+
"multiple_choice": ["acc", "acc_norm"],
|
| 90 |
+
"generate_until": ["exact_match"],
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def register_metric(**args):
|
| 95 |
+
# TODO: do we want to enforce a certain interface to registered metrics?
|
| 96 |
+
def decorate(fn):
|
| 97 |
+
assert "metric" in args
|
| 98 |
+
name = args["metric"]
|
| 99 |
+
|
| 100 |
+
for key, registry in [
|
| 101 |
+
("metric", METRIC_REGISTRY),
|
| 102 |
+
("higher_is_better", HIGHER_IS_BETTER_REGISTRY),
|
| 103 |
+
("aggregation", METRIC_AGGREGATION_REGISTRY),
|
| 104 |
+
]:
|
| 105 |
+
if key in args:
|
| 106 |
+
value = args[key]
|
| 107 |
+
assert value not in registry, (
|
| 108 |
+
f"{key} named '{value}' conflicts with existing registered {key}!"
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
if key == "metric":
|
| 112 |
+
registry[name] = fn
|
| 113 |
+
elif key == "aggregation":
|
| 114 |
+
registry[name] = AGGREGATION_REGISTRY[value]
|
| 115 |
+
else:
|
| 116 |
+
registry[name] = value
|
| 117 |
+
|
| 118 |
+
return fn
|
| 119 |
+
|
| 120 |
+
return decorate
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def get_metric(name: str, hf_evaluate_metric=False) -> Callable:
|
| 124 |
+
if not hf_evaluate_metric:
|
| 125 |
+
if name in METRIC_REGISTRY:
|
| 126 |
+
return METRIC_REGISTRY[name]
|
| 127 |
+
else:
|
| 128 |
+
eval_logger.warning(
|
| 129 |
+
f"Could not find registered metric '{name}' in lm-eval, searching in HF Evaluate library..."
|
| 130 |
+
)
|
| 131 |
+
|
| 132 |
+
try:
|
| 133 |
+
metric_object = hf_evaluate.load(name)
|
| 134 |
+
return metric_object.compute
|
| 135 |
+
except Exception:
|
| 136 |
+
eval_logger.error(
|
| 137 |
+
f"{name} not found in the evaluate library! Please check https://huggingface.co/evaluate-metric",
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def register_aggregation(name: str):
|
| 142 |
+
def decorate(fn):
|
| 143 |
+
assert name not in AGGREGATION_REGISTRY, (
|
| 144 |
+
f"aggregation named '{name}' conflicts with existing registered aggregation!"
|
| 145 |
+
)
|
| 146 |
+
|
| 147 |
+
AGGREGATION_REGISTRY[name] = fn
|
| 148 |
+
return fn
|
| 149 |
+
|
| 150 |
+
return decorate
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def get_aggregation(name: str) -> Callable[[], Dict[str, Callable]]:
|
| 154 |
+
try:
|
| 155 |
+
return AGGREGATION_REGISTRY[name]
|
| 156 |
+
except KeyError:
|
| 157 |
+
eval_logger.warning(f"{name} not a registered aggregation metric!")
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def get_metric_aggregation(name: str) -> Callable[[], Dict[str, Callable]]:
|
| 161 |
+
try:
|
| 162 |
+
return METRIC_AGGREGATION_REGISTRY[name]
|
| 163 |
+
except KeyError:
|
| 164 |
+
eval_logger.warning(f"{name} metric is not assigned a default aggregation!")
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def is_higher_better(metric_name) -> bool:
|
| 168 |
+
try:
|
| 169 |
+
return HIGHER_IS_BETTER_REGISTRY[metric_name]
|
| 170 |
+
except KeyError:
|
| 171 |
+
eval_logger.warning(
|
| 172 |
+
f"higher_is_better not specified for metric '{metric_name}'!"
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def register_filter(name):
|
| 177 |
+
def decorate(cls):
|
| 178 |
+
if name in FILTER_REGISTRY:
|
| 179 |
+
eval_logger.info(
|
| 180 |
+
f"Registering filter `{name}` that is already in Registry {FILTER_REGISTRY}"
|
| 181 |
+
)
|
| 182 |
+
FILTER_REGISTRY[name] = cls
|
| 183 |
+
return cls
|
| 184 |
+
|
| 185 |
+
return decorate
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def get_filter(filter_name: Union[str, Callable]) -> Callable:
|
| 189 |
+
try:
|
| 190 |
+
return FILTER_REGISTRY[filter_name]
|
| 191 |
+
except KeyError as e:
|
| 192 |
+
if callable(filter_name):
|
| 193 |
+
return filter_name
|
| 194 |
+
else:
|
| 195 |
+
eval_logger.warning(f"filter `{filter_name}` is not registered!")
|
| 196 |
+
raise e
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/accelerate-1.12.0.dist-info/licenses/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc
ADDED
|
Binary file (12 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc
ADDED
|
Binary file (14.9 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc
ADDED
|
Binary file (21.5 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc
ADDED
|
Binary file (32.8 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc
ADDED
|
Binary file (24.8 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/_version.cpython-312.pyc
ADDED
|
Binary file (336 Bytes). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc
ADDED
|
Binary file (28.4 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc
ADDED
|
Binary file (69.3 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
from .tz import *
|
| 3 |
+
from .tz import __doc__
|
| 4 |
+
|
| 5 |
+
__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
|
| 6 |
+
"tzstr", "tzical", "tzwin", "tzwinlocal", "gettz",
|
| 7 |
+
"enfold", "datetime_ambiguous", "datetime_exists",
|
| 8 |
+
"resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"]
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class DeprecatedTzFormatWarning(Warning):
|
| 12 |
+
"""Warning raised when time zones are parsed from deprecated formats."""
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/_common.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from six import PY2
|
| 2 |
+
|
| 3 |
+
from functools import wraps
|
| 4 |
+
|
| 5 |
+
from datetime import datetime, timedelta, tzinfo
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
ZERO = timedelta(0)
|
| 9 |
+
|
| 10 |
+
__all__ = ['tzname_in_python2', 'enfold']
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def tzname_in_python2(namefunc):
|
| 14 |
+
"""Change unicode output into bytestrings in Python 2
|
| 15 |
+
|
| 16 |
+
tzname() API changed in Python 3. It used to return bytes, but was changed
|
| 17 |
+
to unicode strings
|
| 18 |
+
"""
|
| 19 |
+
if PY2:
|
| 20 |
+
@wraps(namefunc)
|
| 21 |
+
def adjust_encoding(*args, **kwargs):
|
| 22 |
+
name = namefunc(*args, **kwargs)
|
| 23 |
+
if name is not None:
|
| 24 |
+
name = name.encode()
|
| 25 |
+
|
| 26 |
+
return name
|
| 27 |
+
|
| 28 |
+
return adjust_encoding
|
| 29 |
+
else:
|
| 30 |
+
return namefunc
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
# The following is adapted from Alexander Belopolsky's tz library
|
| 34 |
+
# https://github.com/abalkin/tz
|
| 35 |
+
if hasattr(datetime, 'fold'):
|
| 36 |
+
# This is the pre-python 3.6 fold situation
|
| 37 |
+
def enfold(dt, fold=1):
|
| 38 |
+
"""
|
| 39 |
+
Provides a unified interface for assigning the ``fold`` attribute to
|
| 40 |
+
datetimes both before and after the implementation of PEP-495.
|
| 41 |
+
|
| 42 |
+
:param fold:
|
| 43 |
+
The value for the ``fold`` attribute in the returned datetime. This
|
| 44 |
+
should be either 0 or 1.
|
| 45 |
+
|
| 46 |
+
:return:
|
| 47 |
+
Returns an object for which ``getattr(dt, 'fold', 0)`` returns
|
| 48 |
+
``fold`` for all versions of Python. In versions prior to
|
| 49 |
+
Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
|
| 50 |
+
subclass of :py:class:`datetime.datetime` with the ``fold``
|
| 51 |
+
attribute added, if ``fold`` is 1.
|
| 52 |
+
|
| 53 |
+
.. versionadded:: 2.6.0
|
| 54 |
+
"""
|
| 55 |
+
return dt.replace(fold=fold)
|
| 56 |
+
|
| 57 |
+
else:
|
| 58 |
+
class _DatetimeWithFold(datetime):
|
| 59 |
+
"""
|
| 60 |
+
This is a class designed to provide a PEP 495-compliant interface for
|
| 61 |
+
Python versions before 3.6. It is used only for dates in a fold, so
|
| 62 |
+
the ``fold`` attribute is fixed at ``1``.
|
| 63 |
+
|
| 64 |
+
.. versionadded:: 2.6.0
|
| 65 |
+
"""
|
| 66 |
+
__slots__ = ()
|
| 67 |
+
|
| 68 |
+
def replace(self, *args, **kwargs):
|
| 69 |
+
"""
|
| 70 |
+
Return a datetime with the same attributes, except for those
|
| 71 |
+
attributes given new values by whichever keyword arguments are
|
| 72 |
+
specified. Note that tzinfo=None can be specified to create a naive
|
| 73 |
+
datetime from an aware datetime with no conversion of date and time
|
| 74 |
+
data.
|
| 75 |
+
|
| 76 |
+
This is reimplemented in ``_DatetimeWithFold`` because pypy3 will
|
| 77 |
+
return a ``datetime.datetime`` even if ``fold`` is unchanged.
|
| 78 |
+
"""
|
| 79 |
+
argnames = (
|
| 80 |
+
'year', 'month', 'day', 'hour', 'minute', 'second',
|
| 81 |
+
'microsecond', 'tzinfo'
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
for arg, argname in zip(args, argnames):
|
| 85 |
+
if argname in kwargs:
|
| 86 |
+
raise TypeError('Duplicate argument: {}'.format(argname))
|
| 87 |
+
|
| 88 |
+
kwargs[argname] = arg
|
| 89 |
+
|
| 90 |
+
for argname in argnames:
|
| 91 |
+
if argname not in kwargs:
|
| 92 |
+
kwargs[argname] = getattr(self, argname)
|
| 93 |
+
|
| 94 |
+
dt_class = self.__class__ if kwargs.get('fold', 1) else datetime
|
| 95 |
+
|
| 96 |
+
return dt_class(**kwargs)
|
| 97 |
+
|
| 98 |
+
@property
|
| 99 |
+
def fold(self):
|
| 100 |
+
return 1
|
| 101 |
+
|
| 102 |
+
def enfold(dt, fold=1):
|
| 103 |
+
"""
|
| 104 |
+
Provides a unified interface for assigning the ``fold`` attribute to
|
| 105 |
+
datetimes both before and after the implementation of PEP-495.
|
| 106 |
+
|
| 107 |
+
:param fold:
|
| 108 |
+
The value for the ``fold`` attribute in the returned datetime. This
|
| 109 |
+
should be either 0 or 1.
|
| 110 |
+
|
| 111 |
+
:return:
|
| 112 |
+
Returns an object for which ``getattr(dt, 'fold', 0)`` returns
|
| 113 |
+
``fold`` for all versions of Python. In versions prior to
|
| 114 |
+
Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
|
| 115 |
+
subclass of :py:class:`datetime.datetime` with the ``fold``
|
| 116 |
+
attribute added, if ``fold`` is 1.
|
| 117 |
+
|
| 118 |
+
.. versionadded:: 2.6.0
|
| 119 |
+
"""
|
| 120 |
+
if getattr(dt, 'fold', 0) == fold:
|
| 121 |
+
return dt
|
| 122 |
+
|
| 123 |
+
args = dt.timetuple()[:6]
|
| 124 |
+
args += (dt.microsecond, dt.tzinfo)
|
| 125 |
+
|
| 126 |
+
if fold:
|
| 127 |
+
return _DatetimeWithFold(*args)
|
| 128 |
+
else:
|
| 129 |
+
return datetime(*args)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def _validate_fromutc_inputs(f):
|
| 133 |
+
"""
|
| 134 |
+
The CPython version of ``fromutc`` checks that the input is a ``datetime``
|
| 135 |
+
object and that ``self`` is attached as its ``tzinfo``.
|
| 136 |
+
"""
|
| 137 |
+
@wraps(f)
|
| 138 |
+
def fromutc(self, dt):
|
| 139 |
+
if not isinstance(dt, datetime):
|
| 140 |
+
raise TypeError("fromutc() requires a datetime argument")
|
| 141 |
+
if dt.tzinfo is not self:
|
| 142 |
+
raise ValueError("dt.tzinfo is not self")
|
| 143 |
+
|
| 144 |
+
return f(self, dt)
|
| 145 |
+
|
| 146 |
+
return fromutc
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class _tzinfo(tzinfo):
|
| 150 |
+
"""
|
| 151 |
+
Base class for all ``dateutil`` ``tzinfo`` objects.
|
| 152 |
+
"""
|
| 153 |
+
|
| 154 |
+
def is_ambiguous(self, dt):
|
| 155 |
+
"""
|
| 156 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 157 |
+
zone.
|
| 158 |
+
|
| 159 |
+
:param dt:
|
| 160 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
:return:
|
| 164 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 165 |
+
|
| 166 |
+
.. versionadded:: 2.6.0
|
| 167 |
+
"""
|
| 168 |
+
|
| 169 |
+
dt = dt.replace(tzinfo=self)
|
| 170 |
+
|
| 171 |
+
wall_0 = enfold(dt, fold=0)
|
| 172 |
+
wall_1 = enfold(dt, fold=1)
|
| 173 |
+
|
| 174 |
+
same_offset = wall_0.utcoffset() == wall_1.utcoffset()
|
| 175 |
+
same_dt = wall_0.replace(tzinfo=None) == wall_1.replace(tzinfo=None)
|
| 176 |
+
|
| 177 |
+
return same_dt and not same_offset
|
| 178 |
+
|
| 179 |
+
def _fold_status(self, dt_utc, dt_wall):
|
| 180 |
+
"""
|
| 181 |
+
Determine the fold status of a "wall" datetime, given a representation
|
| 182 |
+
of the same datetime as a (naive) UTC datetime. This is calculated based
|
| 183 |
+
on the assumption that ``dt.utcoffset() - dt.dst()`` is constant for all
|
| 184 |
+
datetimes, and that this offset is the actual number of hours separating
|
| 185 |
+
``dt_utc`` and ``dt_wall``.
|
| 186 |
+
|
| 187 |
+
:param dt_utc:
|
| 188 |
+
Representation of the datetime as UTC
|
| 189 |
+
|
| 190 |
+
:param dt_wall:
|
| 191 |
+
Representation of the datetime as "wall time". This parameter must
|
| 192 |
+
either have a `fold` attribute or have a fold-naive
|
| 193 |
+
:class:`datetime.tzinfo` attached, otherwise the calculation may
|
| 194 |
+
fail.
|
| 195 |
+
"""
|
| 196 |
+
if self.is_ambiguous(dt_wall):
|
| 197 |
+
delta_wall = dt_wall - dt_utc
|
| 198 |
+
_fold = int(delta_wall == (dt_utc.utcoffset() - dt_utc.dst()))
|
| 199 |
+
else:
|
| 200 |
+
_fold = 0
|
| 201 |
+
|
| 202 |
+
return _fold
|
| 203 |
+
|
| 204 |
+
def _fold(self, dt):
|
| 205 |
+
return getattr(dt, 'fold', 0)
|
| 206 |
+
|
| 207 |
+
def _fromutc(self, dt):
|
| 208 |
+
"""
|
| 209 |
+
Given a timezone-aware datetime in a given timezone, calculates a
|
| 210 |
+
timezone-aware datetime in a new timezone.
|
| 211 |
+
|
| 212 |
+
Since this is the one time that we *know* we have an unambiguous
|
| 213 |
+
datetime object, we take this opportunity to determine whether the
|
| 214 |
+
datetime is ambiguous and in a "fold" state (e.g. if it's the first
|
| 215 |
+
occurrence, chronologically, of the ambiguous datetime).
|
| 216 |
+
|
| 217 |
+
:param dt:
|
| 218 |
+
A timezone-aware :class:`datetime.datetime` object.
|
| 219 |
+
"""
|
| 220 |
+
|
| 221 |
+
# Re-implement the algorithm from Python's datetime.py
|
| 222 |
+
dtoff = dt.utcoffset()
|
| 223 |
+
if dtoff is None:
|
| 224 |
+
raise ValueError("fromutc() requires a non-None utcoffset() "
|
| 225 |
+
"result")
|
| 226 |
+
|
| 227 |
+
# The original datetime.py code assumes that `dst()` defaults to
|
| 228 |
+
# zero during ambiguous times. PEP 495 inverts this presumption, so
|
| 229 |
+
# for pre-PEP 495 versions of python, we need to tweak the algorithm.
|
| 230 |
+
dtdst = dt.dst()
|
| 231 |
+
if dtdst is None:
|
| 232 |
+
raise ValueError("fromutc() requires a non-None dst() result")
|
| 233 |
+
delta = dtoff - dtdst
|
| 234 |
+
|
| 235 |
+
dt += delta
|
| 236 |
+
# Set fold=1 so we can default to being in the fold for
|
| 237 |
+
# ambiguous dates.
|
| 238 |
+
dtdst = enfold(dt, fold=1).dst()
|
| 239 |
+
if dtdst is None:
|
| 240 |
+
raise ValueError("fromutc(): dt.dst gave inconsistent "
|
| 241 |
+
"results; cannot convert")
|
| 242 |
+
return dt + dtdst
|
| 243 |
+
|
| 244 |
+
@_validate_fromutc_inputs
|
| 245 |
+
def fromutc(self, dt):
|
| 246 |
+
"""
|
| 247 |
+
Given a timezone-aware datetime in a given timezone, calculates a
|
| 248 |
+
timezone-aware datetime in a new timezone.
|
| 249 |
+
|
| 250 |
+
Since this is the one time that we *know* we have an unambiguous
|
| 251 |
+
datetime object, we take this opportunity to determine whether the
|
| 252 |
+
datetime is ambiguous and in a "fold" state (e.g. if it's the first
|
| 253 |
+
occurrence, chronologically, of the ambiguous datetime).
|
| 254 |
+
|
| 255 |
+
:param dt:
|
| 256 |
+
A timezone-aware :class:`datetime.datetime` object.
|
| 257 |
+
"""
|
| 258 |
+
dt_wall = self._fromutc(dt)
|
| 259 |
+
|
| 260 |
+
# Calculate the fold status given the two datetimes.
|
| 261 |
+
_fold = self._fold_status(dt, dt_wall)
|
| 262 |
+
|
| 263 |
+
# Set the default fold value for ambiguous dates
|
| 264 |
+
return enfold(dt_wall, fold=_fold)
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
class tzrangebase(_tzinfo):
|
| 268 |
+
"""
|
| 269 |
+
This is an abstract base class for time zones represented by an annual
|
| 270 |
+
transition into and out of DST. Child classes should implement the following
|
| 271 |
+
methods:
|
| 272 |
+
|
| 273 |
+
* ``__init__(self, *args, **kwargs)``
|
| 274 |
+
* ``transitions(self, year)`` - this is expected to return a tuple of
|
| 275 |
+
datetimes representing the DST on and off transitions in standard
|
| 276 |
+
time.
|
| 277 |
+
|
| 278 |
+
A fully initialized ``tzrangebase`` subclass should also provide the
|
| 279 |
+
following attributes:
|
| 280 |
+
* ``hasdst``: Boolean whether or not the zone uses DST.
|
| 281 |
+
* ``_dst_offset`` / ``_std_offset``: :class:`datetime.timedelta` objects
|
| 282 |
+
representing the respective UTC offsets.
|
| 283 |
+
* ``_dst_abbr`` / ``_std_abbr``: Strings representing the timezone short
|
| 284 |
+
abbreviations in DST and STD, respectively.
|
| 285 |
+
* ``_hasdst``: Whether or not the zone has DST.
|
| 286 |
+
|
| 287 |
+
.. versionadded:: 2.6.0
|
| 288 |
+
"""
|
| 289 |
+
def __init__(self):
|
| 290 |
+
raise NotImplementedError('tzrangebase is an abstract base class')
|
| 291 |
+
|
| 292 |
+
def utcoffset(self, dt):
|
| 293 |
+
isdst = self._isdst(dt)
|
| 294 |
+
|
| 295 |
+
if isdst is None:
|
| 296 |
+
return None
|
| 297 |
+
elif isdst:
|
| 298 |
+
return self._dst_offset
|
| 299 |
+
else:
|
| 300 |
+
return self._std_offset
|
| 301 |
+
|
| 302 |
+
def dst(self, dt):
|
| 303 |
+
isdst = self._isdst(dt)
|
| 304 |
+
|
| 305 |
+
if isdst is None:
|
| 306 |
+
return None
|
| 307 |
+
elif isdst:
|
| 308 |
+
return self._dst_base_offset
|
| 309 |
+
else:
|
| 310 |
+
return ZERO
|
| 311 |
+
|
| 312 |
+
@tzname_in_python2
|
| 313 |
+
def tzname(self, dt):
|
| 314 |
+
if self._isdst(dt):
|
| 315 |
+
return self._dst_abbr
|
| 316 |
+
else:
|
| 317 |
+
return self._std_abbr
|
| 318 |
+
|
| 319 |
+
def fromutc(self, dt):
|
| 320 |
+
""" Given a datetime in UTC, return local time """
|
| 321 |
+
if not isinstance(dt, datetime):
|
| 322 |
+
raise TypeError("fromutc() requires a datetime argument")
|
| 323 |
+
|
| 324 |
+
if dt.tzinfo is not self:
|
| 325 |
+
raise ValueError("dt.tzinfo is not self")
|
| 326 |
+
|
| 327 |
+
# Get transitions - if there are none, fixed offset
|
| 328 |
+
transitions = self.transitions(dt.year)
|
| 329 |
+
if transitions is None:
|
| 330 |
+
return dt + self.utcoffset(dt)
|
| 331 |
+
|
| 332 |
+
# Get the transition times in UTC
|
| 333 |
+
dston, dstoff = transitions
|
| 334 |
+
|
| 335 |
+
dston -= self._std_offset
|
| 336 |
+
dstoff -= self._std_offset
|
| 337 |
+
|
| 338 |
+
utc_transitions = (dston, dstoff)
|
| 339 |
+
dt_utc = dt.replace(tzinfo=None)
|
| 340 |
+
|
| 341 |
+
isdst = self._naive_isdst(dt_utc, utc_transitions)
|
| 342 |
+
|
| 343 |
+
if isdst:
|
| 344 |
+
dt_wall = dt + self._dst_offset
|
| 345 |
+
else:
|
| 346 |
+
dt_wall = dt + self._std_offset
|
| 347 |
+
|
| 348 |
+
_fold = int(not isdst and self.is_ambiguous(dt_wall))
|
| 349 |
+
|
| 350 |
+
return enfold(dt_wall, fold=_fold)
|
| 351 |
+
|
| 352 |
+
def is_ambiguous(self, dt):
|
| 353 |
+
"""
|
| 354 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 355 |
+
zone.
|
| 356 |
+
|
| 357 |
+
:param dt:
|
| 358 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
:return:
|
| 362 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 363 |
+
|
| 364 |
+
.. versionadded:: 2.6.0
|
| 365 |
+
"""
|
| 366 |
+
if not self.hasdst:
|
| 367 |
+
return False
|
| 368 |
+
|
| 369 |
+
start, end = self.transitions(dt.year)
|
| 370 |
+
|
| 371 |
+
dt = dt.replace(tzinfo=None)
|
| 372 |
+
return (end <= dt < end + self._dst_base_offset)
|
| 373 |
+
|
| 374 |
+
def _isdst(self, dt):
|
| 375 |
+
if not self.hasdst:
|
| 376 |
+
return False
|
| 377 |
+
elif dt is None:
|
| 378 |
+
return None
|
| 379 |
+
|
| 380 |
+
transitions = self.transitions(dt.year)
|
| 381 |
+
|
| 382 |
+
if transitions is None:
|
| 383 |
+
return False
|
| 384 |
+
|
| 385 |
+
dt = dt.replace(tzinfo=None)
|
| 386 |
+
|
| 387 |
+
isdst = self._naive_isdst(dt, transitions)
|
| 388 |
+
|
| 389 |
+
# Handle ambiguous dates
|
| 390 |
+
if not isdst and self.is_ambiguous(dt):
|
| 391 |
+
return not self._fold(dt)
|
| 392 |
+
else:
|
| 393 |
+
return isdst
|
| 394 |
+
|
| 395 |
+
def _naive_isdst(self, dt, transitions):
|
| 396 |
+
dston, dstoff = transitions
|
| 397 |
+
|
| 398 |
+
dt = dt.replace(tzinfo=None)
|
| 399 |
+
|
| 400 |
+
if dston < dstoff:
|
| 401 |
+
isdst = dston <= dt < dstoff
|
| 402 |
+
else:
|
| 403 |
+
isdst = not dstoff <= dt < dston
|
| 404 |
+
|
| 405 |
+
return isdst
|
| 406 |
+
|
| 407 |
+
@property
|
| 408 |
+
def _dst_base_offset(self):
|
| 409 |
+
return self._dst_offset - self._std_offset
|
| 410 |
+
|
| 411 |
+
__hash__ = None
|
| 412 |
+
|
| 413 |
+
def __ne__(self, other):
|
| 414 |
+
return not (self == other)
|
| 415 |
+
|
| 416 |
+
def __repr__(self):
|
| 417 |
+
return "%s(...)" % self.__class__.__name__
|
| 418 |
+
|
| 419 |
+
__reduce__ = object.__reduce__
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/_factories.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import timedelta
|
| 2 |
+
import weakref
|
| 3 |
+
from collections import OrderedDict
|
| 4 |
+
|
| 5 |
+
from six.moves import _thread
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class _TzSingleton(type):
|
| 9 |
+
def __init__(cls, *args, **kwargs):
|
| 10 |
+
cls.__instance = None
|
| 11 |
+
super(_TzSingleton, cls).__init__(*args, **kwargs)
|
| 12 |
+
|
| 13 |
+
def __call__(cls):
|
| 14 |
+
if cls.__instance is None:
|
| 15 |
+
cls.__instance = super(_TzSingleton, cls).__call__()
|
| 16 |
+
return cls.__instance
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class _TzFactory(type):
|
| 20 |
+
def instance(cls, *args, **kwargs):
|
| 21 |
+
"""Alternate constructor that returns a fresh instance"""
|
| 22 |
+
return type.__call__(cls, *args, **kwargs)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class _TzOffsetFactory(_TzFactory):
|
| 26 |
+
def __init__(cls, *args, **kwargs):
|
| 27 |
+
cls.__instances = weakref.WeakValueDictionary()
|
| 28 |
+
cls.__strong_cache = OrderedDict()
|
| 29 |
+
cls.__strong_cache_size = 8
|
| 30 |
+
|
| 31 |
+
cls._cache_lock = _thread.allocate_lock()
|
| 32 |
+
|
| 33 |
+
def __call__(cls, name, offset):
|
| 34 |
+
if isinstance(offset, timedelta):
|
| 35 |
+
key = (name, offset.total_seconds())
|
| 36 |
+
else:
|
| 37 |
+
key = (name, offset)
|
| 38 |
+
|
| 39 |
+
instance = cls.__instances.get(key, None)
|
| 40 |
+
if instance is None:
|
| 41 |
+
instance = cls.__instances.setdefault(key,
|
| 42 |
+
cls.instance(name, offset))
|
| 43 |
+
|
| 44 |
+
# This lock may not be necessary in Python 3. See GH issue #901
|
| 45 |
+
with cls._cache_lock:
|
| 46 |
+
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
| 47 |
+
|
| 48 |
+
# Remove an item if the strong cache is overpopulated
|
| 49 |
+
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
| 50 |
+
cls.__strong_cache.popitem(last=False)
|
| 51 |
+
|
| 52 |
+
return instance
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class _TzStrFactory(_TzFactory):
|
| 56 |
+
def __init__(cls, *args, **kwargs):
|
| 57 |
+
cls.__instances = weakref.WeakValueDictionary()
|
| 58 |
+
cls.__strong_cache = OrderedDict()
|
| 59 |
+
cls.__strong_cache_size = 8
|
| 60 |
+
|
| 61 |
+
cls.__cache_lock = _thread.allocate_lock()
|
| 62 |
+
|
| 63 |
+
def __call__(cls, s, posix_offset=False):
|
| 64 |
+
key = (s, posix_offset)
|
| 65 |
+
instance = cls.__instances.get(key, None)
|
| 66 |
+
|
| 67 |
+
if instance is None:
|
| 68 |
+
instance = cls.__instances.setdefault(key,
|
| 69 |
+
cls.instance(s, posix_offset))
|
| 70 |
+
|
| 71 |
+
# This lock may not be necessary in Python 3. See GH issue #901
|
| 72 |
+
with cls.__cache_lock:
|
| 73 |
+
cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
|
| 74 |
+
|
| 75 |
+
# Remove an item if the strong cache is overpopulated
|
| 76 |
+
if len(cls.__strong_cache) > cls.__strong_cache_size:
|
| 77 |
+
cls.__strong_cache.popitem(last=False)
|
| 78 |
+
|
| 79 |
+
return instance
|
| 80 |
+
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/tz.py
ADDED
|
@@ -0,0 +1,1849 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
This module offers timezone implementations subclassing the abstract
|
| 4 |
+
:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format
|
| 5 |
+
files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,
|
| 6 |
+
etc), TZ environment string (in all known formats), given ranges (with help
|
| 7 |
+
from relative deltas), local machine timezone, fixed offset timezone, and UTC
|
| 8 |
+
timezone.
|
| 9 |
+
"""
|
| 10 |
+
import datetime
|
| 11 |
+
import struct
|
| 12 |
+
import time
|
| 13 |
+
import sys
|
| 14 |
+
import os
|
| 15 |
+
import bisect
|
| 16 |
+
import weakref
|
| 17 |
+
from collections import OrderedDict
|
| 18 |
+
|
| 19 |
+
import six
|
| 20 |
+
from six import string_types
|
| 21 |
+
from six.moves import _thread
|
| 22 |
+
from ._common import tzname_in_python2, _tzinfo
|
| 23 |
+
from ._common import tzrangebase, enfold
|
| 24 |
+
from ._common import _validate_fromutc_inputs
|
| 25 |
+
|
| 26 |
+
from ._factories import _TzSingleton, _TzOffsetFactory
|
| 27 |
+
from ._factories import _TzStrFactory
|
| 28 |
+
try:
|
| 29 |
+
from .win import tzwin, tzwinlocal
|
| 30 |
+
except ImportError:
|
| 31 |
+
tzwin = tzwinlocal = None
|
| 32 |
+
|
| 33 |
+
# For warning about rounding tzinfo
|
| 34 |
+
from warnings import warn
|
| 35 |
+
|
| 36 |
+
ZERO = datetime.timedelta(0)
|
| 37 |
+
EPOCH = datetime.datetime(1970, 1, 1, 0, 0)
|
| 38 |
+
EPOCHORDINAL = EPOCH.toordinal()
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
@six.add_metaclass(_TzSingleton)
|
| 42 |
+
class tzutc(datetime.tzinfo):
|
| 43 |
+
"""
|
| 44 |
+
This is a tzinfo object that represents the UTC time zone.
|
| 45 |
+
|
| 46 |
+
**Examples:**
|
| 47 |
+
|
| 48 |
+
.. doctest::
|
| 49 |
+
|
| 50 |
+
>>> from datetime import *
|
| 51 |
+
>>> from dateutil.tz import *
|
| 52 |
+
|
| 53 |
+
>>> datetime.now()
|
| 54 |
+
datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
|
| 55 |
+
|
| 56 |
+
>>> datetime.now(tzutc())
|
| 57 |
+
datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
|
| 58 |
+
|
| 59 |
+
>>> datetime.now(tzutc()).tzname()
|
| 60 |
+
'UTC'
|
| 61 |
+
|
| 62 |
+
.. versionchanged:: 2.7.0
|
| 63 |
+
``tzutc()`` is now a singleton, so the result of ``tzutc()`` will
|
| 64 |
+
always return the same object.
|
| 65 |
+
|
| 66 |
+
.. doctest::
|
| 67 |
+
|
| 68 |
+
>>> from dateutil.tz import tzutc, UTC
|
| 69 |
+
>>> tzutc() is tzutc()
|
| 70 |
+
True
|
| 71 |
+
>>> tzutc() is UTC
|
| 72 |
+
True
|
| 73 |
+
"""
|
| 74 |
+
def utcoffset(self, dt):
|
| 75 |
+
return ZERO
|
| 76 |
+
|
| 77 |
+
def dst(self, dt):
|
| 78 |
+
return ZERO
|
| 79 |
+
|
| 80 |
+
@tzname_in_python2
|
| 81 |
+
def tzname(self, dt):
|
| 82 |
+
return "UTC"
|
| 83 |
+
|
| 84 |
+
def is_ambiguous(self, dt):
|
| 85 |
+
"""
|
| 86 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 87 |
+
zone.
|
| 88 |
+
|
| 89 |
+
:param dt:
|
| 90 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
:return:
|
| 94 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 95 |
+
|
| 96 |
+
.. versionadded:: 2.6.0
|
| 97 |
+
"""
|
| 98 |
+
return False
|
| 99 |
+
|
| 100 |
+
@_validate_fromutc_inputs
|
| 101 |
+
def fromutc(self, dt):
|
| 102 |
+
"""
|
| 103 |
+
Fast track version of fromutc() returns the original ``dt`` object for
|
| 104 |
+
any valid :py:class:`datetime.datetime` object.
|
| 105 |
+
"""
|
| 106 |
+
return dt
|
| 107 |
+
|
| 108 |
+
def __eq__(self, other):
|
| 109 |
+
if not isinstance(other, (tzutc, tzoffset)):
|
| 110 |
+
return NotImplemented
|
| 111 |
+
|
| 112 |
+
return (isinstance(other, tzutc) or
|
| 113 |
+
(isinstance(other, tzoffset) and other._offset == ZERO))
|
| 114 |
+
|
| 115 |
+
__hash__ = None
|
| 116 |
+
|
| 117 |
+
def __ne__(self, other):
|
| 118 |
+
return not (self == other)
|
| 119 |
+
|
| 120 |
+
def __repr__(self):
|
| 121 |
+
return "%s()" % self.__class__.__name__
|
| 122 |
+
|
| 123 |
+
__reduce__ = object.__reduce__
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
#: Convenience constant providing a :class:`tzutc()` instance
|
| 127 |
+
#:
|
| 128 |
+
#: .. versionadded:: 2.7.0
|
| 129 |
+
UTC = tzutc()
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
@six.add_metaclass(_TzOffsetFactory)
|
| 133 |
+
class tzoffset(datetime.tzinfo):
|
| 134 |
+
"""
|
| 135 |
+
A simple class for representing a fixed offset from UTC.
|
| 136 |
+
|
| 137 |
+
:param name:
|
| 138 |
+
The timezone name, to be returned when ``tzname()`` is called.
|
| 139 |
+
:param offset:
|
| 140 |
+
The time zone offset in seconds, or (since version 2.6.0, represented
|
| 141 |
+
as a :py:class:`datetime.timedelta` object).
|
| 142 |
+
"""
|
| 143 |
+
def __init__(self, name, offset):
|
| 144 |
+
self._name = name
|
| 145 |
+
|
| 146 |
+
try:
|
| 147 |
+
# Allow a timedelta
|
| 148 |
+
offset = offset.total_seconds()
|
| 149 |
+
except (TypeError, AttributeError):
|
| 150 |
+
pass
|
| 151 |
+
|
| 152 |
+
self._offset = datetime.timedelta(seconds=_get_supported_offset(offset))
|
| 153 |
+
|
| 154 |
+
def utcoffset(self, dt):
|
| 155 |
+
return self._offset
|
| 156 |
+
|
| 157 |
+
def dst(self, dt):
|
| 158 |
+
return ZERO
|
| 159 |
+
|
| 160 |
+
@tzname_in_python2
|
| 161 |
+
def tzname(self, dt):
|
| 162 |
+
return self._name
|
| 163 |
+
|
| 164 |
+
@_validate_fromutc_inputs
|
| 165 |
+
def fromutc(self, dt):
|
| 166 |
+
return dt + self._offset
|
| 167 |
+
|
| 168 |
+
def is_ambiguous(self, dt):
|
| 169 |
+
"""
|
| 170 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 171 |
+
zone.
|
| 172 |
+
|
| 173 |
+
:param dt:
|
| 174 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 175 |
+
:return:
|
| 176 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 177 |
+
|
| 178 |
+
.. versionadded:: 2.6.0
|
| 179 |
+
"""
|
| 180 |
+
return False
|
| 181 |
+
|
| 182 |
+
def __eq__(self, other):
|
| 183 |
+
if not isinstance(other, tzoffset):
|
| 184 |
+
return NotImplemented
|
| 185 |
+
|
| 186 |
+
return self._offset == other._offset
|
| 187 |
+
|
| 188 |
+
__hash__ = None
|
| 189 |
+
|
| 190 |
+
def __ne__(self, other):
|
| 191 |
+
return not (self == other)
|
| 192 |
+
|
| 193 |
+
def __repr__(self):
|
| 194 |
+
return "%s(%s, %s)" % (self.__class__.__name__,
|
| 195 |
+
repr(self._name),
|
| 196 |
+
int(self._offset.total_seconds()))
|
| 197 |
+
|
| 198 |
+
__reduce__ = object.__reduce__
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
class tzlocal(_tzinfo):
|
| 202 |
+
"""
|
| 203 |
+
A :class:`tzinfo` subclass built around the ``time`` timezone functions.
|
| 204 |
+
"""
|
| 205 |
+
def __init__(self):
|
| 206 |
+
super(tzlocal, self).__init__()
|
| 207 |
+
|
| 208 |
+
self._std_offset = datetime.timedelta(seconds=-time.timezone)
|
| 209 |
+
if time.daylight:
|
| 210 |
+
self._dst_offset = datetime.timedelta(seconds=-time.altzone)
|
| 211 |
+
else:
|
| 212 |
+
self._dst_offset = self._std_offset
|
| 213 |
+
|
| 214 |
+
self._dst_saved = self._dst_offset - self._std_offset
|
| 215 |
+
self._hasdst = bool(self._dst_saved)
|
| 216 |
+
self._tznames = tuple(time.tzname)
|
| 217 |
+
|
| 218 |
+
def utcoffset(self, dt):
|
| 219 |
+
if dt is None and self._hasdst:
|
| 220 |
+
return None
|
| 221 |
+
|
| 222 |
+
if self._isdst(dt):
|
| 223 |
+
return self._dst_offset
|
| 224 |
+
else:
|
| 225 |
+
return self._std_offset
|
| 226 |
+
|
| 227 |
+
def dst(self, dt):
|
| 228 |
+
if dt is None and self._hasdst:
|
| 229 |
+
return None
|
| 230 |
+
|
| 231 |
+
if self._isdst(dt):
|
| 232 |
+
return self._dst_offset - self._std_offset
|
| 233 |
+
else:
|
| 234 |
+
return ZERO
|
| 235 |
+
|
| 236 |
+
@tzname_in_python2
|
| 237 |
+
def tzname(self, dt):
|
| 238 |
+
return self._tznames[self._isdst(dt)]
|
| 239 |
+
|
| 240 |
+
def is_ambiguous(self, dt):
|
| 241 |
+
"""
|
| 242 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 243 |
+
zone.
|
| 244 |
+
|
| 245 |
+
:param dt:
|
| 246 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
:return:
|
| 250 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 251 |
+
|
| 252 |
+
.. versionadded:: 2.6.0
|
| 253 |
+
"""
|
| 254 |
+
naive_dst = self._naive_is_dst(dt)
|
| 255 |
+
return (not naive_dst and
|
| 256 |
+
(naive_dst != self._naive_is_dst(dt - self._dst_saved)))
|
| 257 |
+
|
| 258 |
+
def _naive_is_dst(self, dt):
|
| 259 |
+
timestamp = _datetime_to_timestamp(dt)
|
| 260 |
+
return time.localtime(timestamp + time.timezone).tm_isdst
|
| 261 |
+
|
| 262 |
+
def _isdst(self, dt, fold_naive=True):
|
| 263 |
+
# We can't use mktime here. It is unstable when deciding if
|
| 264 |
+
# the hour near to a change is DST or not.
|
| 265 |
+
#
|
| 266 |
+
# timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,
|
| 267 |
+
# dt.minute, dt.second, dt.weekday(), 0, -1))
|
| 268 |
+
# return time.localtime(timestamp).tm_isdst
|
| 269 |
+
#
|
| 270 |
+
# The code above yields the following result:
|
| 271 |
+
#
|
| 272 |
+
# >>> import tz, datetime
|
| 273 |
+
# >>> t = tz.tzlocal()
|
| 274 |
+
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
| 275 |
+
# 'BRDT'
|
| 276 |
+
# >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
|
| 277 |
+
# 'BRST'
|
| 278 |
+
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
| 279 |
+
# 'BRST'
|
| 280 |
+
# >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()
|
| 281 |
+
# 'BRDT'
|
| 282 |
+
# >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
|
| 283 |
+
# 'BRDT'
|
| 284 |
+
#
|
| 285 |
+
# Here is a more stable implementation:
|
| 286 |
+
#
|
| 287 |
+
if not self._hasdst:
|
| 288 |
+
return False
|
| 289 |
+
|
| 290 |
+
# Check for ambiguous times:
|
| 291 |
+
dstval = self._naive_is_dst(dt)
|
| 292 |
+
fold = getattr(dt, 'fold', None)
|
| 293 |
+
|
| 294 |
+
if self.is_ambiguous(dt):
|
| 295 |
+
if fold is not None:
|
| 296 |
+
return not self._fold(dt)
|
| 297 |
+
else:
|
| 298 |
+
return True
|
| 299 |
+
|
| 300 |
+
return dstval
|
| 301 |
+
|
| 302 |
+
def __eq__(self, other):
|
| 303 |
+
if isinstance(other, tzlocal):
|
| 304 |
+
return (self._std_offset == other._std_offset and
|
| 305 |
+
self._dst_offset == other._dst_offset)
|
| 306 |
+
elif isinstance(other, tzutc):
|
| 307 |
+
return (not self._hasdst and
|
| 308 |
+
self._tznames[0] in {'UTC', 'GMT'} and
|
| 309 |
+
self._std_offset == ZERO)
|
| 310 |
+
elif isinstance(other, tzoffset):
|
| 311 |
+
return (not self._hasdst and
|
| 312 |
+
self._tznames[0] == other._name and
|
| 313 |
+
self._std_offset == other._offset)
|
| 314 |
+
else:
|
| 315 |
+
return NotImplemented
|
| 316 |
+
|
| 317 |
+
__hash__ = None
|
| 318 |
+
|
| 319 |
+
def __ne__(self, other):
|
| 320 |
+
return not (self == other)
|
| 321 |
+
|
| 322 |
+
def __repr__(self):
|
| 323 |
+
return "%s()" % self.__class__.__name__
|
| 324 |
+
|
| 325 |
+
__reduce__ = object.__reduce__
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
class _ttinfo(object):
|
| 329 |
+
__slots__ = ["offset", "delta", "isdst", "abbr",
|
| 330 |
+
"isstd", "isgmt", "dstoffset"]
|
| 331 |
+
|
| 332 |
+
def __init__(self):
|
| 333 |
+
for attr in self.__slots__:
|
| 334 |
+
setattr(self, attr, None)
|
| 335 |
+
|
| 336 |
+
def __repr__(self):
|
| 337 |
+
l = []
|
| 338 |
+
for attr in self.__slots__:
|
| 339 |
+
value = getattr(self, attr)
|
| 340 |
+
if value is not None:
|
| 341 |
+
l.append("%s=%s" % (attr, repr(value)))
|
| 342 |
+
return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
|
| 343 |
+
|
| 344 |
+
def __eq__(self, other):
|
| 345 |
+
if not isinstance(other, _ttinfo):
|
| 346 |
+
return NotImplemented
|
| 347 |
+
|
| 348 |
+
return (self.offset == other.offset and
|
| 349 |
+
self.delta == other.delta and
|
| 350 |
+
self.isdst == other.isdst and
|
| 351 |
+
self.abbr == other.abbr and
|
| 352 |
+
self.isstd == other.isstd and
|
| 353 |
+
self.isgmt == other.isgmt and
|
| 354 |
+
self.dstoffset == other.dstoffset)
|
| 355 |
+
|
| 356 |
+
__hash__ = None
|
| 357 |
+
|
| 358 |
+
def __ne__(self, other):
|
| 359 |
+
return not (self == other)
|
| 360 |
+
|
| 361 |
+
def __getstate__(self):
|
| 362 |
+
state = {}
|
| 363 |
+
for name in self.__slots__:
|
| 364 |
+
state[name] = getattr(self, name, None)
|
| 365 |
+
return state
|
| 366 |
+
|
| 367 |
+
def __setstate__(self, state):
|
| 368 |
+
for name in self.__slots__:
|
| 369 |
+
if name in state:
|
| 370 |
+
setattr(self, name, state[name])
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
class _tzfile(object):
|
| 374 |
+
"""
|
| 375 |
+
Lightweight class for holding the relevant transition and time zone
|
| 376 |
+
information read from binary tzfiles.
|
| 377 |
+
"""
|
| 378 |
+
attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list',
|
| 379 |
+
'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first']
|
| 380 |
+
|
| 381 |
+
def __init__(self, **kwargs):
|
| 382 |
+
for attr in self.attrs:
|
| 383 |
+
setattr(self, attr, kwargs.get(attr, None))
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
class tzfile(_tzinfo):
|
| 387 |
+
"""
|
| 388 |
+
This is a ``tzinfo`` subclass that allows one to use the ``tzfile(5)``
|
| 389 |
+
format timezone files to extract current and historical zone information.
|
| 390 |
+
|
| 391 |
+
:param fileobj:
|
| 392 |
+
This can be an opened file stream or a file name that the time zone
|
| 393 |
+
information can be read from.
|
| 394 |
+
|
| 395 |
+
:param filename:
|
| 396 |
+
This is an optional parameter specifying the source of the time zone
|
| 397 |
+
information in the event that ``fileobj`` is a file object. If omitted
|
| 398 |
+
and ``fileobj`` is a file stream, this parameter will be set either to
|
| 399 |
+
``fileobj``'s ``name`` attribute or to ``repr(fileobj)``.
|
| 400 |
+
|
| 401 |
+
See `Sources for Time Zone and Daylight Saving Time Data
|
| 402 |
+
<https://data.iana.org/time-zones/tz-link.html>`_ for more information.
|
| 403 |
+
Time zone files can be compiled from the `IANA Time Zone database files
|
| 404 |
+
<https://www.iana.org/time-zones>`_ with the `zic time zone compiler
|
| 405 |
+
<https://www.freebsd.org/cgi/man.cgi?query=zic&sektion=8>`_
|
| 406 |
+
|
| 407 |
+
.. note::
|
| 408 |
+
|
| 409 |
+
Only construct a ``tzfile`` directly if you have a specific timezone
|
| 410 |
+
file on disk that you want to read into a Python ``tzinfo`` object.
|
| 411 |
+
If you want to get a ``tzfile`` representing a specific IANA zone,
|
| 412 |
+
(e.g. ``'America/New_York'``), you should call
|
| 413 |
+
:func:`dateutil.tz.gettz` with the zone identifier.
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
**Examples:**
|
| 417 |
+
|
| 418 |
+
Using the US Eastern time zone as an example, we can see that a ``tzfile``
|
| 419 |
+
provides time zone information for the standard Daylight Saving offsets:
|
| 420 |
+
|
| 421 |
+
.. testsetup:: tzfile
|
| 422 |
+
|
| 423 |
+
from dateutil.tz import gettz
|
| 424 |
+
from datetime import datetime
|
| 425 |
+
|
| 426 |
+
.. doctest:: tzfile
|
| 427 |
+
|
| 428 |
+
>>> NYC = gettz('America/New_York')
|
| 429 |
+
>>> NYC
|
| 430 |
+
tzfile('/usr/share/zoneinfo/America/New_York')
|
| 431 |
+
|
| 432 |
+
>>> print(datetime(2016, 1, 3, tzinfo=NYC)) # EST
|
| 433 |
+
2016-01-03 00:00:00-05:00
|
| 434 |
+
|
| 435 |
+
>>> print(datetime(2016, 7, 7, tzinfo=NYC)) # EDT
|
| 436 |
+
2016-07-07 00:00:00-04:00
|
| 437 |
+
|
| 438 |
+
|
| 439 |
+
The ``tzfile`` structure contains a fully history of the time zone,
|
| 440 |
+
so historical dates will also have the right offsets. For example, before
|
| 441 |
+
the adoption of the UTC standards, New York used local solar mean time:
|
| 442 |
+
|
| 443 |
+
.. doctest:: tzfile
|
| 444 |
+
|
| 445 |
+
>>> print(datetime(1901, 4, 12, tzinfo=NYC)) # LMT
|
| 446 |
+
1901-04-12 00:00:00-04:56
|
| 447 |
+
|
| 448 |
+
And during World War II, New York was on "Eastern War Time", which was a
|
| 449 |
+
state of permanent daylight saving time:
|
| 450 |
+
|
| 451 |
+
.. doctest:: tzfile
|
| 452 |
+
|
| 453 |
+
>>> print(datetime(1944, 2, 7, tzinfo=NYC)) # EWT
|
| 454 |
+
1944-02-07 00:00:00-04:00
|
| 455 |
+
|
| 456 |
+
"""
|
| 457 |
+
|
| 458 |
+
def __init__(self, fileobj, filename=None):
|
| 459 |
+
super(tzfile, self).__init__()
|
| 460 |
+
|
| 461 |
+
file_opened_here = False
|
| 462 |
+
if isinstance(fileobj, string_types):
|
| 463 |
+
self._filename = fileobj
|
| 464 |
+
fileobj = open(fileobj, 'rb')
|
| 465 |
+
file_opened_here = True
|
| 466 |
+
elif filename is not None:
|
| 467 |
+
self._filename = filename
|
| 468 |
+
elif hasattr(fileobj, "name"):
|
| 469 |
+
self._filename = fileobj.name
|
| 470 |
+
else:
|
| 471 |
+
self._filename = repr(fileobj)
|
| 472 |
+
|
| 473 |
+
if fileobj is not None:
|
| 474 |
+
if not file_opened_here:
|
| 475 |
+
fileobj = _nullcontext(fileobj)
|
| 476 |
+
|
| 477 |
+
with fileobj as file_stream:
|
| 478 |
+
tzobj = self._read_tzfile(file_stream)
|
| 479 |
+
|
| 480 |
+
self._set_tzdata(tzobj)
|
| 481 |
+
|
| 482 |
+
def _set_tzdata(self, tzobj):
|
| 483 |
+
""" Set the time zone data of this object from a _tzfile object """
|
| 484 |
+
# Copy the relevant attributes over as private attributes
|
| 485 |
+
for attr in _tzfile.attrs:
|
| 486 |
+
setattr(self, '_' + attr, getattr(tzobj, attr))
|
| 487 |
+
|
| 488 |
+
def _read_tzfile(self, fileobj):
|
| 489 |
+
out = _tzfile()
|
| 490 |
+
|
| 491 |
+
# From tzfile(5):
|
| 492 |
+
#
|
| 493 |
+
# The time zone information files used by tzset(3)
|
| 494 |
+
# begin with the magic characters "TZif" to identify
|
| 495 |
+
# them as time zone information files, followed by
|
| 496 |
+
# sixteen bytes reserved for future use, followed by
|
| 497 |
+
# six four-byte values of type long, written in a
|
| 498 |
+
# ``standard'' byte order (the high-order byte
|
| 499 |
+
# of the value is written first).
|
| 500 |
+
if fileobj.read(4).decode() != "TZif":
|
| 501 |
+
raise ValueError("magic not found")
|
| 502 |
+
|
| 503 |
+
fileobj.read(16)
|
| 504 |
+
|
| 505 |
+
(
|
| 506 |
+
# The number of UTC/local indicators stored in the file.
|
| 507 |
+
ttisgmtcnt,
|
| 508 |
+
|
| 509 |
+
# The number of standard/wall indicators stored in the file.
|
| 510 |
+
ttisstdcnt,
|
| 511 |
+
|
| 512 |
+
# The number of leap seconds for which data is
|
| 513 |
+
# stored in the file.
|
| 514 |
+
leapcnt,
|
| 515 |
+
|
| 516 |
+
# The number of "transition times" for which data
|
| 517 |
+
# is stored in the file.
|
| 518 |
+
timecnt,
|
| 519 |
+
|
| 520 |
+
# The number of "local time types" for which data
|
| 521 |
+
# is stored in the file (must not be zero).
|
| 522 |
+
typecnt,
|
| 523 |
+
|
| 524 |
+
# The number of characters of "time zone
|
| 525 |
+
# abbreviation strings" stored in the file.
|
| 526 |
+
charcnt,
|
| 527 |
+
|
| 528 |
+
) = struct.unpack(">6l", fileobj.read(24))
|
| 529 |
+
|
| 530 |
+
# The above header is followed by tzh_timecnt four-byte
|
| 531 |
+
# values of type long, sorted in ascending order.
|
| 532 |
+
# These values are written in ``standard'' byte order.
|
| 533 |
+
# Each is used as a transition time (as returned by
|
| 534 |
+
# time(2)) at which the rules for computing local time
|
| 535 |
+
# change.
|
| 536 |
+
|
| 537 |
+
if timecnt:
|
| 538 |
+
out.trans_list_utc = list(struct.unpack(">%dl" % timecnt,
|
| 539 |
+
fileobj.read(timecnt*4)))
|
| 540 |
+
else:
|
| 541 |
+
out.trans_list_utc = []
|
| 542 |
+
|
| 543 |
+
# Next come tzh_timecnt one-byte values of type unsigned
|
| 544 |
+
# char; each one tells which of the different types of
|
| 545 |
+
# ``local time'' types described in the file is associated
|
| 546 |
+
# with the same-indexed transition time. These values
|
| 547 |
+
# serve as indices into an array of ttinfo structures that
|
| 548 |
+
# appears next in the file.
|
| 549 |
+
|
| 550 |
+
if timecnt:
|
| 551 |
+
out.trans_idx = struct.unpack(">%dB" % timecnt,
|
| 552 |
+
fileobj.read(timecnt))
|
| 553 |
+
else:
|
| 554 |
+
out.trans_idx = []
|
| 555 |
+
|
| 556 |
+
# Each ttinfo structure is written as a four-byte value
|
| 557 |
+
# for tt_gmtoff of type long, in a standard byte
|
| 558 |
+
# order, followed by a one-byte value for tt_isdst
|
| 559 |
+
# and a one-byte value for tt_abbrind. In each
|
| 560 |
+
# structure, tt_gmtoff gives the number of
|
| 561 |
+
# seconds to be added to UTC, tt_isdst tells whether
|
| 562 |
+
# tm_isdst should be set by localtime(3), and
|
| 563 |
+
# tt_abbrind serves as an index into the array of
|
| 564 |
+
# time zone abbreviation characters that follow the
|
| 565 |
+
# ttinfo structure(s) in the file.
|
| 566 |
+
|
| 567 |
+
ttinfo = []
|
| 568 |
+
|
| 569 |
+
for i in range(typecnt):
|
| 570 |
+
ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
|
| 571 |
+
|
| 572 |
+
abbr = fileobj.read(charcnt).decode()
|
| 573 |
+
|
| 574 |
+
# Then there are tzh_leapcnt pairs of four-byte
|
| 575 |
+
# values, written in standard byte order; the
|
| 576 |
+
# first value of each pair gives the time (as
|
| 577 |
+
# returned by time(2)) at which a leap second
|
| 578 |
+
# occurs; the second gives the total number of
|
| 579 |
+
# leap seconds to be applied after the given time.
|
| 580 |
+
# The pairs of values are sorted in ascending order
|
| 581 |
+
# by time.
|
| 582 |
+
|
| 583 |
+
# Not used, for now (but seek for correct file position)
|
| 584 |
+
if leapcnt:
|
| 585 |
+
fileobj.seek(leapcnt * 8, os.SEEK_CUR)
|
| 586 |
+
|
| 587 |
+
# Then there are tzh_ttisstdcnt standard/wall
|
| 588 |
+
# indicators, each stored as a one-byte value;
|
| 589 |
+
# they tell whether the transition times associated
|
| 590 |
+
# with local time types were specified as standard
|
| 591 |
+
# time or wall clock time, and are used when
|
| 592 |
+
# a time zone file is used in handling POSIX-style
|
| 593 |
+
# time zone environment variables.
|
| 594 |
+
|
| 595 |
+
if ttisstdcnt:
|
| 596 |
+
isstd = struct.unpack(">%db" % ttisstdcnt,
|
| 597 |
+
fileobj.read(ttisstdcnt))
|
| 598 |
+
|
| 599 |
+
# Finally, there are tzh_ttisgmtcnt UTC/local
|
| 600 |
+
# indicators, each stored as a one-byte value;
|
| 601 |
+
# they tell whether the transition times associated
|
| 602 |
+
# with local time types were specified as UTC or
|
| 603 |
+
# local time, and are used when a time zone file
|
| 604 |
+
# is used in handling POSIX-style time zone envi-
|
| 605 |
+
# ronment variables.
|
| 606 |
+
|
| 607 |
+
if ttisgmtcnt:
|
| 608 |
+
isgmt = struct.unpack(">%db" % ttisgmtcnt,
|
| 609 |
+
fileobj.read(ttisgmtcnt))
|
| 610 |
+
|
| 611 |
+
# Build ttinfo list
|
| 612 |
+
out.ttinfo_list = []
|
| 613 |
+
for i in range(typecnt):
|
| 614 |
+
gmtoff, isdst, abbrind = ttinfo[i]
|
| 615 |
+
gmtoff = _get_supported_offset(gmtoff)
|
| 616 |
+
tti = _ttinfo()
|
| 617 |
+
tti.offset = gmtoff
|
| 618 |
+
tti.dstoffset = datetime.timedelta(0)
|
| 619 |
+
tti.delta = datetime.timedelta(seconds=gmtoff)
|
| 620 |
+
tti.isdst = isdst
|
| 621 |
+
tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)]
|
| 622 |
+
tti.isstd = (ttisstdcnt > i and isstd[i] != 0)
|
| 623 |
+
tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0)
|
| 624 |
+
out.ttinfo_list.append(tti)
|
| 625 |
+
|
| 626 |
+
# Replace ttinfo indexes for ttinfo objects.
|
| 627 |
+
out.trans_idx = [out.ttinfo_list[idx] for idx in out.trans_idx]
|
| 628 |
+
|
| 629 |
+
# Set standard, dst, and before ttinfos. before will be
|
| 630 |
+
# used when a given time is before any transitions,
|
| 631 |
+
# and will be set to the first non-dst ttinfo, or to
|
| 632 |
+
# the first dst, if all of them are dst.
|
| 633 |
+
out.ttinfo_std = None
|
| 634 |
+
out.ttinfo_dst = None
|
| 635 |
+
out.ttinfo_before = None
|
| 636 |
+
if out.ttinfo_list:
|
| 637 |
+
if not out.trans_list_utc:
|
| 638 |
+
out.ttinfo_std = out.ttinfo_first = out.ttinfo_list[0]
|
| 639 |
+
else:
|
| 640 |
+
for i in range(timecnt-1, -1, -1):
|
| 641 |
+
tti = out.trans_idx[i]
|
| 642 |
+
if not out.ttinfo_std and not tti.isdst:
|
| 643 |
+
out.ttinfo_std = tti
|
| 644 |
+
elif not out.ttinfo_dst and tti.isdst:
|
| 645 |
+
out.ttinfo_dst = tti
|
| 646 |
+
|
| 647 |
+
if out.ttinfo_std and out.ttinfo_dst:
|
| 648 |
+
break
|
| 649 |
+
else:
|
| 650 |
+
if out.ttinfo_dst and not out.ttinfo_std:
|
| 651 |
+
out.ttinfo_std = out.ttinfo_dst
|
| 652 |
+
|
| 653 |
+
for tti in out.ttinfo_list:
|
| 654 |
+
if not tti.isdst:
|
| 655 |
+
out.ttinfo_before = tti
|
| 656 |
+
break
|
| 657 |
+
else:
|
| 658 |
+
out.ttinfo_before = out.ttinfo_list[0]
|
| 659 |
+
|
| 660 |
+
# Now fix transition times to become relative to wall time.
|
| 661 |
+
#
|
| 662 |
+
# I'm not sure about this. In my tests, the tz source file
|
| 663 |
+
# is setup to wall time, and in the binary file isstd and
|
| 664 |
+
# isgmt are off, so it should be in wall time. OTOH, it's
|
| 665 |
+
# always in gmt time. Let me know if you have comments
|
| 666 |
+
# about this.
|
| 667 |
+
lastdst = None
|
| 668 |
+
lastoffset = None
|
| 669 |
+
lastdstoffset = None
|
| 670 |
+
lastbaseoffset = None
|
| 671 |
+
out.trans_list = []
|
| 672 |
+
|
| 673 |
+
for i, tti in enumerate(out.trans_idx):
|
| 674 |
+
offset = tti.offset
|
| 675 |
+
dstoffset = 0
|
| 676 |
+
|
| 677 |
+
if lastdst is not None:
|
| 678 |
+
if tti.isdst:
|
| 679 |
+
if not lastdst:
|
| 680 |
+
dstoffset = offset - lastoffset
|
| 681 |
+
|
| 682 |
+
if not dstoffset and lastdstoffset:
|
| 683 |
+
dstoffset = lastdstoffset
|
| 684 |
+
|
| 685 |
+
tti.dstoffset = datetime.timedelta(seconds=dstoffset)
|
| 686 |
+
lastdstoffset = dstoffset
|
| 687 |
+
|
| 688 |
+
# If a time zone changes its base offset during a DST transition,
|
| 689 |
+
# then you need to adjust by the previous base offset to get the
|
| 690 |
+
# transition time in local time. Otherwise you use the current
|
| 691 |
+
# base offset. Ideally, I would have some mathematical proof of
|
| 692 |
+
# why this is true, but I haven't really thought about it enough.
|
| 693 |
+
baseoffset = offset - dstoffset
|
| 694 |
+
adjustment = baseoffset
|
| 695 |
+
if (lastbaseoffset is not None and baseoffset != lastbaseoffset
|
| 696 |
+
and tti.isdst != lastdst):
|
| 697 |
+
# The base DST has changed
|
| 698 |
+
adjustment = lastbaseoffset
|
| 699 |
+
|
| 700 |
+
lastdst = tti.isdst
|
| 701 |
+
lastoffset = offset
|
| 702 |
+
lastbaseoffset = baseoffset
|
| 703 |
+
|
| 704 |
+
out.trans_list.append(out.trans_list_utc[i] + adjustment)
|
| 705 |
+
|
| 706 |
+
out.trans_idx = tuple(out.trans_idx)
|
| 707 |
+
out.trans_list = tuple(out.trans_list)
|
| 708 |
+
out.trans_list_utc = tuple(out.trans_list_utc)
|
| 709 |
+
|
| 710 |
+
return out
|
| 711 |
+
|
| 712 |
+
def _find_last_transition(self, dt, in_utc=False):
|
| 713 |
+
# If there's no list, there are no transitions to find
|
| 714 |
+
if not self._trans_list:
|
| 715 |
+
return None
|
| 716 |
+
|
| 717 |
+
timestamp = _datetime_to_timestamp(dt)
|
| 718 |
+
|
| 719 |
+
# Find where the timestamp fits in the transition list - if the
|
| 720 |
+
# timestamp is a transition time, it's part of the "after" period.
|
| 721 |
+
trans_list = self._trans_list_utc if in_utc else self._trans_list
|
| 722 |
+
idx = bisect.bisect_right(trans_list, timestamp)
|
| 723 |
+
|
| 724 |
+
# We want to know when the previous transition was, so subtract off 1
|
| 725 |
+
return idx - 1
|
| 726 |
+
|
| 727 |
+
def _get_ttinfo(self, idx):
|
| 728 |
+
# For no list or after the last transition, default to _ttinfo_std
|
| 729 |
+
if idx is None or (idx + 1) >= len(self._trans_list):
|
| 730 |
+
return self._ttinfo_std
|
| 731 |
+
|
| 732 |
+
# If there is a list and the time is before it, return _ttinfo_before
|
| 733 |
+
if idx < 0:
|
| 734 |
+
return self._ttinfo_before
|
| 735 |
+
|
| 736 |
+
return self._trans_idx[idx]
|
| 737 |
+
|
| 738 |
+
def _find_ttinfo(self, dt):
|
| 739 |
+
idx = self._resolve_ambiguous_time(dt)
|
| 740 |
+
|
| 741 |
+
return self._get_ttinfo(idx)
|
| 742 |
+
|
| 743 |
+
def fromutc(self, dt):
|
| 744 |
+
"""
|
| 745 |
+
The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`.
|
| 746 |
+
|
| 747 |
+
:param dt:
|
| 748 |
+
A :py:class:`datetime.datetime` object.
|
| 749 |
+
|
| 750 |
+
:raises TypeError:
|
| 751 |
+
Raised if ``dt`` is not a :py:class:`datetime.datetime` object.
|
| 752 |
+
|
| 753 |
+
:raises ValueError:
|
| 754 |
+
Raised if this is called with a ``dt`` which does not have this
|
| 755 |
+
``tzinfo`` attached.
|
| 756 |
+
|
| 757 |
+
:return:
|
| 758 |
+
Returns a :py:class:`datetime.datetime` object representing the
|
| 759 |
+
wall time in ``self``'s time zone.
|
| 760 |
+
"""
|
| 761 |
+
# These isinstance checks are in datetime.tzinfo, so we'll preserve
|
| 762 |
+
# them, even if we don't care about duck typing.
|
| 763 |
+
if not isinstance(dt, datetime.datetime):
|
| 764 |
+
raise TypeError("fromutc() requires a datetime argument")
|
| 765 |
+
|
| 766 |
+
if dt.tzinfo is not self:
|
| 767 |
+
raise ValueError("dt.tzinfo is not self")
|
| 768 |
+
|
| 769 |
+
# First treat UTC as wall time and get the transition we're in.
|
| 770 |
+
idx = self._find_last_transition(dt, in_utc=True)
|
| 771 |
+
tti = self._get_ttinfo(idx)
|
| 772 |
+
|
| 773 |
+
dt_out = dt + datetime.timedelta(seconds=tti.offset)
|
| 774 |
+
|
| 775 |
+
fold = self.is_ambiguous(dt_out, idx=idx)
|
| 776 |
+
|
| 777 |
+
return enfold(dt_out, fold=int(fold))
|
| 778 |
+
|
| 779 |
+
def is_ambiguous(self, dt, idx=None):
|
| 780 |
+
"""
|
| 781 |
+
Whether or not the "wall time" of a given datetime is ambiguous in this
|
| 782 |
+
zone.
|
| 783 |
+
|
| 784 |
+
:param dt:
|
| 785 |
+
A :py:class:`datetime.datetime`, naive or time zone aware.
|
| 786 |
+
|
| 787 |
+
|
| 788 |
+
:return:
|
| 789 |
+
Returns ``True`` if ambiguous, ``False`` otherwise.
|
| 790 |
+
|
| 791 |
+
.. versionadded:: 2.6.0
|
| 792 |
+
"""
|
| 793 |
+
if idx is None:
|
| 794 |
+
idx = self._find_last_transition(dt)
|
| 795 |
+
|
| 796 |
+
# Calculate the difference in offsets from current to previous
|
| 797 |
+
timestamp = _datetime_to_timestamp(dt)
|
| 798 |
+
tti = self._get_ttinfo(idx)
|
| 799 |
+
|
| 800 |
+
if idx is None or idx <= 0:
|
| 801 |
+
return False
|
| 802 |
+
|
| 803 |
+
od = self._get_ttinfo(idx - 1).offset - tti.offset
|
| 804 |
+
tt = self._trans_list[idx] # Transition time
|
| 805 |
+
|
| 806 |
+
return timestamp < tt + od
|
| 807 |
+
|
| 808 |
+
def _resolve_ambiguous_time(self, dt):
|
| 809 |
+
idx = self._find_last_transition(dt)
|
| 810 |
+
|
| 811 |
+
# If we have no transitions, return the index
|
| 812 |
+
_fold = self._fold(dt)
|
| 813 |
+
if idx is None or idx == 0:
|
| 814 |
+
return idx
|
| 815 |
+
|
| 816 |
+
# If it's ambiguous and we're in a fold, shift to a different index.
|
| 817 |
+
idx_offset = int(not _fold and self.is_ambiguous(dt, idx))
|
| 818 |
+
|
| 819 |
+
return idx - idx_offset
|
| 820 |
+
|
| 821 |
+
def utcoffset(self, dt):
|
| 822 |
+
if dt is None:
|
| 823 |
+
return None
|
| 824 |
+
|
| 825 |
+
if not self._ttinfo_std:
|
| 826 |
+
return ZERO
|
| 827 |
+
|
| 828 |
+
return self._find_ttinfo(dt).delta
|
| 829 |
+
|
| 830 |
+
def dst(self, dt):
|
| 831 |
+
if dt is None:
|
| 832 |
+
return None
|
| 833 |
+
|
| 834 |
+
if not self._ttinfo_dst:
|
| 835 |
+
return ZERO
|
| 836 |
+
|
| 837 |
+
tti = self._find_ttinfo(dt)
|
| 838 |
+
|
| 839 |
+
if not tti.isdst:
|
| 840 |
+
return ZERO
|
| 841 |
+
|
| 842 |
+
# The documentation says that utcoffset()-dst() must
|
| 843 |
+
# be constant for every dt.
|
| 844 |
+
return tti.dstoffset
|
| 845 |
+
|
| 846 |
+
@tzname_in_python2
|
| 847 |
+
def tzname(self, dt):
|
| 848 |
+
if not self._ttinfo_std or dt is None:
|
| 849 |
+
return None
|
| 850 |
+
return self._find_ttinfo(dt).abbr
|
| 851 |
+
|
| 852 |
+
def __eq__(self, other):
|
| 853 |
+
if not isinstance(other, tzfile):
|
| 854 |
+
return NotImplemented
|
| 855 |
+
return (self._trans_list == other._trans_list and
|
| 856 |
+
self._trans_idx == other._trans_idx and
|
| 857 |
+
self._ttinfo_list == other._ttinfo_list)
|
| 858 |
+
|
| 859 |
+
__hash__ = None
|
| 860 |
+
|
| 861 |
+
def __ne__(self, other):
|
| 862 |
+
return not (self == other)
|
| 863 |
+
|
| 864 |
+
def __repr__(self):
|
| 865 |
+
return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
|
| 866 |
+
|
| 867 |
+
def __reduce__(self):
|
| 868 |
+
return self.__reduce_ex__(None)
|
| 869 |
+
|
| 870 |
+
def __reduce_ex__(self, protocol):
|
| 871 |
+
return (self.__class__, (None, self._filename), self.__dict__)
|
| 872 |
+
|
| 873 |
+
|
| 874 |
+
class tzrange(tzrangebase):
|
| 875 |
+
"""
|
| 876 |
+
The ``tzrange`` object is a time zone specified by a set of offsets and
|
| 877 |
+
abbreviations, equivalent to the way the ``TZ`` variable can be specified
|
| 878 |
+
in POSIX-like systems, but using Python delta objects to specify DST
|
| 879 |
+
start, end and offsets.
|
| 880 |
+
|
| 881 |
+
:param stdabbr:
|
| 882 |
+
The abbreviation for standard time (e.g. ``'EST'``).
|
| 883 |
+
|
| 884 |
+
:param stdoffset:
|
| 885 |
+
An integer or :class:`datetime.timedelta` object or equivalent
|
| 886 |
+
specifying the base offset from UTC.
|
| 887 |
+
|
| 888 |
+
If unspecified, +00:00 is used.
|
| 889 |
+
|
| 890 |
+
:param dstabbr:
|
| 891 |
+
The abbreviation for DST / "Summer" time (e.g. ``'EDT'``).
|
| 892 |
+
|
| 893 |
+
If specified, with no other DST information, DST is assumed to occur
|
| 894 |
+
and the default behavior or ``dstoffset``, ``start`` and ``end`` is
|
| 895 |
+
used. If unspecified and no other DST information is specified, it
|
| 896 |
+
is assumed that this zone has no DST.
|
| 897 |
+
|
| 898 |
+
If this is unspecified and other DST information is *is* specified,
|
| 899 |
+
DST occurs in the zone but the time zone abbreviation is left
|
| 900 |
+
unchanged.
|
| 901 |
+
|
| 902 |
+
:param dstoffset:
|
| 903 |
+
A an integer or :class:`datetime.timedelta` object or equivalent
|
| 904 |
+
specifying the UTC offset during DST. If unspecified and any other DST
|
| 905 |
+
information is specified, it is assumed to be the STD offset +1 hour.
|
| 906 |
+
|
| 907 |
+
:param start:
|
| 908 |
+
A :class:`relativedelta.relativedelta` object or equivalent specifying
|
| 909 |
+
the time and time of year that daylight savings time starts. To
|
| 910 |
+
specify, for example, that DST starts at 2AM on the 2nd Sunday in
|
| 911 |
+
March, pass:
|
| 912 |
+
|
| 913 |
+
``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))``
|
| 914 |
+
|
| 915 |
+
If unspecified and any other DST information is specified, the default
|
| 916 |
+
value is 2 AM on the first Sunday in April.
|
| 917 |
+
|
| 918 |
+
:param end:
|
| 919 |
+
A :class:`relativedelta.relativedelta` object or equivalent
|
| 920 |
+
representing the time and time of year that daylight savings time
|
| 921 |
+
ends, with the same specification method as in ``start``. One note is
|
| 922 |
+
that this should point to the first time in the *standard* zone, so if
|
| 923 |
+
a transition occurs at 2AM in the DST zone and the clocks are set back
|
| 924 |
+
1 hour to 1AM, set the ``hours`` parameter to +1.
|
| 925 |
+
|
| 926 |
+
|
| 927 |
+
**Examples:**
|
| 928 |
+
|
| 929 |
+
.. testsetup:: tzrange
|
| 930 |
+
|
| 931 |
+
from dateutil.tz import tzrange, tzstr
|
| 932 |
+
|
| 933 |
+
.. doctest:: tzrange
|
| 934 |
+
|
| 935 |
+
>>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
|
| 936 |
+
True
|
| 937 |
+
|
| 938 |
+
>>> from dateutil.relativedelta import *
|
| 939 |
+
>>> range1 = tzrange("EST", -18000, "EDT")
|
| 940 |
+
>>> range2 = tzrange("EST", -18000, "EDT", -14400,
|
| 941 |
+
... relativedelta(hours=+2, month=4, day=1,
|
| 942 |
+
... weekday=SU(+1)),
|
| 943 |
+
... relativedelta(hours=+1, month=10, day=31,
|
| 944 |
+
... weekday=SU(-1)))
|
| 945 |
+
>>> tzstr('EST5EDT') == range1 == range2
|
| 946 |
+
True
|
| 947 |
+
|
| 948 |
+
"""
|
| 949 |
+
def __init__(self, stdabbr, stdoffset=None,
|
| 950 |
+
dstabbr=None, dstoffset=None,
|
| 951 |
+
start=None, end=None):
|
| 952 |
+
|
| 953 |
+
global relativedelta
|
| 954 |
+
from dateutil import relativedelta
|
| 955 |
+
|
| 956 |
+
self._std_abbr = stdabbr
|
| 957 |
+
self._dst_abbr = dstabbr
|
| 958 |
+
|
| 959 |
+
try:
|
| 960 |
+
stdoffset = stdoffset.total_seconds()
|
| 961 |
+
except (TypeError, AttributeError):
|
| 962 |
+
pass
|
| 963 |
+
|
| 964 |
+
try:
|
| 965 |
+
dstoffset = dstoffset.total_seconds()
|
| 966 |
+
except (TypeError, AttributeError):
|
| 967 |
+
pass
|
| 968 |
+
|
| 969 |
+
if stdoffset is not None:
|
| 970 |
+
self._std_offset = datetime.timedelta(seconds=stdoffset)
|
| 971 |
+
else:
|
| 972 |
+
self._std_offset = ZERO
|
| 973 |
+
|
| 974 |
+
if dstoffset is not None:
|
| 975 |
+
self._dst_offset = datetime.timedelta(seconds=dstoffset)
|
| 976 |
+
elif dstabbr and stdoffset is not None:
|
| 977 |
+
self._dst_offset = self._std_offset + datetime.timedelta(hours=+1)
|
| 978 |
+
else:
|
| 979 |
+
self._dst_offset = ZERO
|
| 980 |
+
|
| 981 |
+
if dstabbr and start is None:
|
| 982 |
+
self._start_delta = relativedelta.relativedelta(
|
| 983 |
+
hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
|
| 984 |
+
else:
|
| 985 |
+
self._start_delta = start
|
| 986 |
+
|
| 987 |
+
if dstabbr and end is None:
|
| 988 |
+
self._end_delta = relativedelta.relativedelta(
|
| 989 |
+
hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
|
| 990 |
+
else:
|
| 991 |
+
self._end_delta = end
|
| 992 |
+
|
| 993 |
+
self._dst_base_offset_ = self._dst_offset - self._std_offset
|
| 994 |
+
self.hasdst = bool(self._start_delta)
|
| 995 |
+
|
| 996 |
+
def transitions(self, year):
|
| 997 |
+
"""
|
| 998 |
+
For a given year, get the DST on and off transition times, expressed
|
| 999 |
+
always on the standard time side. For zones with no transitions, this
|
| 1000 |
+
function returns ``None``.
|
| 1001 |
+
|
| 1002 |
+
:param year:
|
| 1003 |
+
The year whose transitions you would like to query.
|
| 1004 |
+
|
| 1005 |
+
:return:
|
| 1006 |
+
Returns a :class:`tuple` of :class:`datetime.datetime` objects,
|
| 1007 |
+
``(dston, dstoff)`` for zones with an annual DST transition, or
|
| 1008 |
+
``None`` for fixed offset zones.
|
| 1009 |
+
"""
|
| 1010 |
+
if not self.hasdst:
|
| 1011 |
+
return None
|
| 1012 |
+
|
| 1013 |
+
base_year = datetime.datetime(year, 1, 1)
|
| 1014 |
+
|
| 1015 |
+
start = base_year + self._start_delta
|
| 1016 |
+
end = base_year + self._end_delta
|
| 1017 |
+
|
| 1018 |
+
return (start, end)
|
| 1019 |
+
|
| 1020 |
+
def __eq__(self, other):
|
| 1021 |
+
if not isinstance(other, tzrange):
|
| 1022 |
+
return NotImplemented
|
| 1023 |
+
|
| 1024 |
+
return (self._std_abbr == other._std_abbr and
|
| 1025 |
+
self._dst_abbr == other._dst_abbr and
|
| 1026 |
+
self._std_offset == other._std_offset and
|
| 1027 |
+
self._dst_offset == other._dst_offset and
|
| 1028 |
+
self._start_delta == other._start_delta and
|
| 1029 |
+
self._end_delta == other._end_delta)
|
| 1030 |
+
|
| 1031 |
+
@property
|
| 1032 |
+
def _dst_base_offset(self):
|
| 1033 |
+
return self._dst_base_offset_
|
| 1034 |
+
|
| 1035 |
+
|
| 1036 |
+
@six.add_metaclass(_TzStrFactory)
|
| 1037 |
+
class tzstr(tzrange):
|
| 1038 |
+
"""
|
| 1039 |
+
``tzstr`` objects are time zone objects specified by a time-zone string as
|
| 1040 |
+
it would be passed to a ``TZ`` variable on POSIX-style systems (see
|
| 1041 |
+
the `GNU C Library: TZ Variable`_ for more details).
|
| 1042 |
+
|
| 1043 |
+
There is one notable exception, which is that POSIX-style time zones use an
|
| 1044 |
+
inverted offset format, so normally ``GMT+3`` would be parsed as an offset
|
| 1045 |
+
3 hours *behind* GMT. The ``tzstr`` time zone object will parse this as an
|
| 1046 |
+
offset 3 hours *ahead* of GMT. If you would like to maintain the POSIX
|
| 1047 |
+
behavior, pass a ``True`` value to ``posix_offset``.
|
| 1048 |
+
|
| 1049 |
+
The :class:`tzrange` object provides the same functionality, but is
|
| 1050 |
+
specified using :class:`relativedelta.relativedelta` objects. rather than
|
| 1051 |
+
strings.
|
| 1052 |
+
|
| 1053 |
+
:param s:
|
| 1054 |
+
A time zone string in ``TZ`` variable format. This can be a
|
| 1055 |
+
:class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:
|
| 1056 |
+
:class:`unicode`) or a stream emitting unicode characters
|
| 1057 |
+
(e.g. :class:`StringIO`).
|
| 1058 |
+
|
| 1059 |
+
:param posix_offset:
|
| 1060 |
+
Optional. If set to ``True``, interpret strings such as ``GMT+3`` or
|
| 1061 |
+
``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the
|
| 1062 |
+
POSIX standard.
|
| 1063 |
+
|
| 1064 |
+
.. caution::
|
| 1065 |
+
|
| 1066 |
+
Prior to version 2.7.0, this function also supported time zones
|
| 1067 |
+
in the format:
|
| 1068 |
+
|
| 1069 |
+
* ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``
|
| 1070 |
+
* ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``
|
| 1071 |
+
|
| 1072 |
+
This format is non-standard and has been deprecated; this function
|
| 1073 |
+
will raise a :class:`DeprecatedTZFormatWarning` until
|
| 1074 |
+
support is removed in a future version.
|
| 1075 |
+
|
| 1076 |
+
.. _`GNU C Library: TZ Variable`:
|
| 1077 |
+
https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
| 1078 |
+
"""
|
| 1079 |
+
def __init__(self, s, posix_offset=False):
|
| 1080 |
+
global parser
|
| 1081 |
+
from dateutil.parser import _parser as parser
|
| 1082 |
+
|
| 1083 |
+
self._s = s
|
| 1084 |
+
|
| 1085 |
+
res = parser._parsetz(s)
|
| 1086 |
+
if res is None or res.any_unused_tokens:
|
| 1087 |
+
raise ValueError("unknown string format")
|
| 1088 |
+
|
| 1089 |
+
# Here we break the compatibility with the TZ variable handling.
|
| 1090 |
+
# GMT-3 actually *means* the timezone -3.
|
| 1091 |
+
if res.stdabbr in ("GMT", "UTC") and not posix_offset:
|
| 1092 |
+
res.stdoffset *= -1
|
| 1093 |
+
|
| 1094 |
+
# We must initialize it first, since _delta() needs
|
| 1095 |
+
# _std_offset and _dst_offset set. Use False in start/end
|
| 1096 |
+
# to avoid building it two times.
|
| 1097 |
+
tzrange.__init__(self, res.stdabbr, res.stdoffset,
|
| 1098 |
+
res.dstabbr, res.dstoffset,
|
| 1099 |
+
start=False, end=False)
|
| 1100 |
+
|
| 1101 |
+
if not res.dstabbr:
|
| 1102 |
+
self._start_delta = None
|
| 1103 |
+
self._end_delta = None
|
| 1104 |
+
else:
|
| 1105 |
+
self._start_delta = self._delta(res.start)
|
| 1106 |
+
if self._start_delta:
|
| 1107 |
+
self._end_delta = self._delta(res.end, isend=1)
|
| 1108 |
+
|
| 1109 |
+
self.hasdst = bool(self._start_delta)
|
| 1110 |
+
|
| 1111 |
+
def _delta(self, x, isend=0):
|
| 1112 |
+
from dateutil import relativedelta
|
| 1113 |
+
kwargs = {}
|
| 1114 |
+
if x.month is not None:
|
| 1115 |
+
kwargs["month"] = x.month
|
| 1116 |
+
if x.weekday is not None:
|
| 1117 |
+
kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week)
|
| 1118 |
+
if x.week > 0:
|
| 1119 |
+
kwargs["day"] = 1
|
| 1120 |
+
else:
|
| 1121 |
+
kwargs["day"] = 31
|
| 1122 |
+
elif x.day:
|
| 1123 |
+
kwargs["day"] = x.day
|
| 1124 |
+
elif x.yday is not None:
|
| 1125 |
+
kwargs["yearday"] = x.yday
|
| 1126 |
+
elif x.jyday is not None:
|
| 1127 |
+
kwargs["nlyearday"] = x.jyday
|
| 1128 |
+
if not kwargs:
|
| 1129 |
+
# Default is to start on first sunday of april, and end
|
| 1130 |
+
# on last sunday of october.
|
| 1131 |
+
if not isend:
|
| 1132 |
+
kwargs["month"] = 4
|
| 1133 |
+
kwargs["day"] = 1
|
| 1134 |
+
kwargs["weekday"] = relativedelta.SU(+1)
|
| 1135 |
+
else:
|
| 1136 |
+
kwargs["month"] = 10
|
| 1137 |
+
kwargs["day"] = 31
|
| 1138 |
+
kwargs["weekday"] = relativedelta.SU(-1)
|
| 1139 |
+
if x.time is not None:
|
| 1140 |
+
kwargs["seconds"] = x.time
|
| 1141 |
+
else:
|
| 1142 |
+
# Default is 2AM.
|
| 1143 |
+
kwargs["seconds"] = 7200
|
| 1144 |
+
if isend:
|
| 1145 |
+
# Convert to standard time, to follow the documented way
|
| 1146 |
+
# of working with the extra hour. See the documentation
|
| 1147 |
+
# of the tzinfo class.
|
| 1148 |
+
delta = self._dst_offset - self._std_offset
|
| 1149 |
+
kwargs["seconds"] -= delta.seconds + delta.days * 86400
|
| 1150 |
+
return relativedelta.relativedelta(**kwargs)
|
| 1151 |
+
|
| 1152 |
+
def __repr__(self):
|
| 1153 |
+
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
| 1154 |
+
|
| 1155 |
+
|
| 1156 |
+
class _tzicalvtzcomp(object):
|
| 1157 |
+
def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
|
| 1158 |
+
tzname=None, rrule=None):
|
| 1159 |
+
self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
|
| 1160 |
+
self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)
|
| 1161 |
+
self.tzoffsetdiff = self.tzoffsetto - self.tzoffsetfrom
|
| 1162 |
+
self.isdst = isdst
|
| 1163 |
+
self.tzname = tzname
|
| 1164 |
+
self.rrule = rrule
|
| 1165 |
+
|
| 1166 |
+
|
| 1167 |
+
class _tzicalvtz(_tzinfo):
|
| 1168 |
+
def __init__(self, tzid, comps=[]):
|
| 1169 |
+
super(_tzicalvtz, self).__init__()
|
| 1170 |
+
|
| 1171 |
+
self._tzid = tzid
|
| 1172 |
+
self._comps = comps
|
| 1173 |
+
self._cachedate = []
|
| 1174 |
+
self._cachecomp = []
|
| 1175 |
+
self._cache_lock = _thread.allocate_lock()
|
| 1176 |
+
|
| 1177 |
+
def _find_comp(self, dt):
|
| 1178 |
+
if len(self._comps) == 1:
|
| 1179 |
+
return self._comps[0]
|
| 1180 |
+
|
| 1181 |
+
dt = dt.replace(tzinfo=None)
|
| 1182 |
+
|
| 1183 |
+
try:
|
| 1184 |
+
with self._cache_lock:
|
| 1185 |
+
return self._cachecomp[self._cachedate.index(
|
| 1186 |
+
(dt, self._fold(dt)))]
|
| 1187 |
+
except ValueError:
|
| 1188 |
+
pass
|
| 1189 |
+
|
| 1190 |
+
lastcompdt = None
|
| 1191 |
+
lastcomp = None
|
| 1192 |
+
|
| 1193 |
+
for comp in self._comps:
|
| 1194 |
+
compdt = self._find_compdt(comp, dt)
|
| 1195 |
+
|
| 1196 |
+
if compdt and (not lastcompdt or lastcompdt < compdt):
|
| 1197 |
+
lastcompdt = compdt
|
| 1198 |
+
lastcomp = comp
|
| 1199 |
+
|
| 1200 |
+
if not lastcomp:
|
| 1201 |
+
# RFC says nothing about what to do when a given
|
| 1202 |
+
# time is before the first onset date. We'll look for the
|
| 1203 |
+
# first standard component, or the first component, if
|
| 1204 |
+
# none is found.
|
| 1205 |
+
for comp in self._comps:
|
| 1206 |
+
if not comp.isdst:
|
| 1207 |
+
lastcomp = comp
|
| 1208 |
+
break
|
| 1209 |
+
else:
|
| 1210 |
+
lastcomp = comp[0]
|
| 1211 |
+
|
| 1212 |
+
with self._cache_lock:
|
| 1213 |
+
self._cachedate.insert(0, (dt, self._fold(dt)))
|
| 1214 |
+
self._cachecomp.insert(0, lastcomp)
|
| 1215 |
+
|
| 1216 |
+
if len(self._cachedate) > 10:
|
| 1217 |
+
self._cachedate.pop()
|
| 1218 |
+
self._cachecomp.pop()
|
| 1219 |
+
|
| 1220 |
+
return lastcomp
|
| 1221 |
+
|
| 1222 |
+
def _find_compdt(self, comp, dt):
|
| 1223 |
+
if comp.tzoffsetdiff < ZERO and self._fold(dt):
|
| 1224 |
+
dt -= comp.tzoffsetdiff
|
| 1225 |
+
|
| 1226 |
+
compdt = comp.rrule.before(dt, inc=True)
|
| 1227 |
+
|
| 1228 |
+
return compdt
|
| 1229 |
+
|
| 1230 |
+
def utcoffset(self, dt):
|
| 1231 |
+
if dt is None:
|
| 1232 |
+
return None
|
| 1233 |
+
|
| 1234 |
+
return self._find_comp(dt).tzoffsetto
|
| 1235 |
+
|
| 1236 |
+
def dst(self, dt):
|
| 1237 |
+
comp = self._find_comp(dt)
|
| 1238 |
+
if comp.isdst:
|
| 1239 |
+
return comp.tzoffsetdiff
|
| 1240 |
+
else:
|
| 1241 |
+
return ZERO
|
| 1242 |
+
|
| 1243 |
+
@tzname_in_python2
|
| 1244 |
+
def tzname(self, dt):
|
| 1245 |
+
return self._find_comp(dt).tzname
|
| 1246 |
+
|
| 1247 |
+
def __repr__(self):
|
| 1248 |
+
return "<tzicalvtz %s>" % repr(self._tzid)
|
| 1249 |
+
|
| 1250 |
+
__reduce__ = object.__reduce__
|
| 1251 |
+
|
| 1252 |
+
|
| 1253 |
+
class tzical(object):
|
| 1254 |
+
"""
|
| 1255 |
+
This object is designed to parse an iCalendar-style ``VTIMEZONE`` structure
|
| 1256 |
+
as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects.
|
| 1257 |
+
|
| 1258 |
+
:param `fileobj`:
|
| 1259 |
+
A file or stream in iCalendar format, which should be UTF-8 encoded
|
| 1260 |
+
with CRLF endings.
|
| 1261 |
+
|
| 1262 |
+
.. _`RFC 5545`: https://tools.ietf.org/html/rfc5545
|
| 1263 |
+
"""
|
| 1264 |
+
def __init__(self, fileobj):
|
| 1265 |
+
global rrule
|
| 1266 |
+
from dateutil import rrule
|
| 1267 |
+
|
| 1268 |
+
if isinstance(fileobj, string_types):
|
| 1269 |
+
self._s = fileobj
|
| 1270 |
+
# ical should be encoded in UTF-8 with CRLF
|
| 1271 |
+
fileobj = open(fileobj, 'r')
|
| 1272 |
+
else:
|
| 1273 |
+
self._s = getattr(fileobj, 'name', repr(fileobj))
|
| 1274 |
+
fileobj = _nullcontext(fileobj)
|
| 1275 |
+
|
| 1276 |
+
self._vtz = {}
|
| 1277 |
+
|
| 1278 |
+
with fileobj as fobj:
|
| 1279 |
+
self._parse_rfc(fobj.read())
|
| 1280 |
+
|
| 1281 |
+
def keys(self):
|
| 1282 |
+
"""
|
| 1283 |
+
Retrieves the available time zones as a list.
|
| 1284 |
+
"""
|
| 1285 |
+
return list(self._vtz.keys())
|
| 1286 |
+
|
| 1287 |
+
def get(self, tzid=None):
|
| 1288 |
+
"""
|
| 1289 |
+
Retrieve a :py:class:`datetime.tzinfo` object by its ``tzid``.
|
| 1290 |
+
|
| 1291 |
+
:param tzid:
|
| 1292 |
+
If there is exactly one time zone available, omitting ``tzid``
|
| 1293 |
+
or passing :py:const:`None` value returns it. Otherwise a valid
|
| 1294 |
+
key (which can be retrieved from :func:`keys`) is required.
|
| 1295 |
+
|
| 1296 |
+
:raises ValueError:
|
| 1297 |
+
Raised if ``tzid`` is not specified but there are either more
|
| 1298 |
+
or fewer than 1 zone defined.
|
| 1299 |
+
|
| 1300 |
+
:returns:
|
| 1301 |
+
Returns either a :py:class:`datetime.tzinfo` object representing
|
| 1302 |
+
the relevant time zone or :py:const:`None` if the ``tzid`` was
|
| 1303 |
+
not found.
|
| 1304 |
+
"""
|
| 1305 |
+
if tzid is None:
|
| 1306 |
+
if len(self._vtz) == 0:
|
| 1307 |
+
raise ValueError("no timezones defined")
|
| 1308 |
+
elif len(self._vtz) > 1:
|
| 1309 |
+
raise ValueError("more than one timezone available")
|
| 1310 |
+
tzid = next(iter(self._vtz))
|
| 1311 |
+
|
| 1312 |
+
return self._vtz.get(tzid)
|
| 1313 |
+
|
| 1314 |
+
def _parse_offset(self, s):
|
| 1315 |
+
s = s.strip()
|
| 1316 |
+
if not s:
|
| 1317 |
+
raise ValueError("empty offset")
|
| 1318 |
+
if s[0] in ('+', '-'):
|
| 1319 |
+
signal = (-1, +1)[s[0] == '+']
|
| 1320 |
+
s = s[1:]
|
| 1321 |
+
else:
|
| 1322 |
+
signal = +1
|
| 1323 |
+
if len(s) == 4:
|
| 1324 |
+
return (int(s[:2]) * 3600 + int(s[2:]) * 60) * signal
|
| 1325 |
+
elif len(s) == 6:
|
| 1326 |
+
return (int(s[:2]) * 3600 + int(s[2:4]) * 60 + int(s[4:])) * signal
|
| 1327 |
+
else:
|
| 1328 |
+
raise ValueError("invalid offset: " + s)
|
| 1329 |
+
|
| 1330 |
+
def _parse_rfc(self, s):
|
| 1331 |
+
lines = s.splitlines()
|
| 1332 |
+
if not lines:
|
| 1333 |
+
raise ValueError("empty string")
|
| 1334 |
+
|
| 1335 |
+
# Unfold
|
| 1336 |
+
i = 0
|
| 1337 |
+
while i < len(lines):
|
| 1338 |
+
line = lines[i].rstrip()
|
| 1339 |
+
if not line:
|
| 1340 |
+
del lines[i]
|
| 1341 |
+
elif i > 0 and line[0] == " ":
|
| 1342 |
+
lines[i-1] += line[1:]
|
| 1343 |
+
del lines[i]
|
| 1344 |
+
else:
|
| 1345 |
+
i += 1
|
| 1346 |
+
|
| 1347 |
+
tzid = None
|
| 1348 |
+
comps = []
|
| 1349 |
+
invtz = False
|
| 1350 |
+
comptype = None
|
| 1351 |
+
for line in lines:
|
| 1352 |
+
if not line:
|
| 1353 |
+
continue
|
| 1354 |
+
name, value = line.split(':', 1)
|
| 1355 |
+
parms = name.split(';')
|
| 1356 |
+
if not parms:
|
| 1357 |
+
raise ValueError("empty property name")
|
| 1358 |
+
name = parms[0].upper()
|
| 1359 |
+
parms = parms[1:]
|
| 1360 |
+
if invtz:
|
| 1361 |
+
if name == "BEGIN":
|
| 1362 |
+
if value in ("STANDARD", "DAYLIGHT"):
|
| 1363 |
+
# Process component
|
| 1364 |
+
pass
|
| 1365 |
+
else:
|
| 1366 |
+
raise ValueError("unknown component: "+value)
|
| 1367 |
+
comptype = value
|
| 1368 |
+
founddtstart = False
|
| 1369 |
+
tzoffsetfrom = None
|
| 1370 |
+
tzoffsetto = None
|
| 1371 |
+
rrulelines = []
|
| 1372 |
+
tzname = None
|
| 1373 |
+
elif name == "END":
|
| 1374 |
+
if value == "VTIMEZONE":
|
| 1375 |
+
if comptype:
|
| 1376 |
+
raise ValueError("component not closed: "+comptype)
|
| 1377 |
+
if not tzid:
|
| 1378 |
+
raise ValueError("mandatory TZID not found")
|
| 1379 |
+
if not comps:
|
| 1380 |
+
raise ValueError(
|
| 1381 |
+
"at least one component is needed")
|
| 1382 |
+
# Process vtimezone
|
| 1383 |
+
self._vtz[tzid] = _tzicalvtz(tzid, comps)
|
| 1384 |
+
invtz = False
|
| 1385 |
+
elif value == comptype:
|
| 1386 |
+
if not founddtstart:
|
| 1387 |
+
raise ValueError("mandatory DTSTART not found")
|
| 1388 |
+
if tzoffsetfrom is None:
|
| 1389 |
+
raise ValueError(
|
| 1390 |
+
"mandatory TZOFFSETFROM not found")
|
| 1391 |
+
if tzoffsetto is None:
|
| 1392 |
+
raise ValueError(
|
| 1393 |
+
"mandatory TZOFFSETFROM not found")
|
| 1394 |
+
# Process component
|
| 1395 |
+
rr = None
|
| 1396 |
+
if rrulelines:
|
| 1397 |
+
rr = rrule.rrulestr("\n".join(rrulelines),
|
| 1398 |
+
compatible=True,
|
| 1399 |
+
ignoretz=True,
|
| 1400 |
+
cache=True)
|
| 1401 |
+
comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto,
|
| 1402 |
+
(comptype == "DAYLIGHT"),
|
| 1403 |
+
tzname, rr)
|
| 1404 |
+
comps.append(comp)
|
| 1405 |
+
comptype = None
|
| 1406 |
+
else:
|
| 1407 |
+
raise ValueError("invalid component end: "+value)
|
| 1408 |
+
elif comptype:
|
| 1409 |
+
if name == "DTSTART":
|
| 1410 |
+
# DTSTART in VTIMEZONE takes a subset of valid RRULE
|
| 1411 |
+
# values under RFC 5545.
|
| 1412 |
+
for parm in parms:
|
| 1413 |
+
if parm != 'VALUE=DATE-TIME':
|
| 1414 |
+
msg = ('Unsupported DTSTART param in ' +
|
| 1415 |
+
'VTIMEZONE: ' + parm)
|
| 1416 |
+
raise ValueError(msg)
|
| 1417 |
+
rrulelines.append(line)
|
| 1418 |
+
founddtstart = True
|
| 1419 |
+
elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"):
|
| 1420 |
+
rrulelines.append(line)
|
| 1421 |
+
elif name == "TZOFFSETFROM":
|
| 1422 |
+
if parms:
|
| 1423 |
+
raise ValueError(
|
| 1424 |
+
"unsupported %s parm: %s " % (name, parms[0]))
|
| 1425 |
+
tzoffsetfrom = self._parse_offset(value)
|
| 1426 |
+
elif name == "TZOFFSETTO":
|
| 1427 |
+
if parms:
|
| 1428 |
+
raise ValueError(
|
| 1429 |
+
"unsupported TZOFFSETTO parm: "+parms[0])
|
| 1430 |
+
tzoffsetto = self._parse_offset(value)
|
| 1431 |
+
elif name == "TZNAME":
|
| 1432 |
+
if parms:
|
| 1433 |
+
raise ValueError(
|
| 1434 |
+
"unsupported TZNAME parm: "+parms[0])
|
| 1435 |
+
tzname = value
|
| 1436 |
+
elif name == "COMMENT":
|
| 1437 |
+
pass
|
| 1438 |
+
else:
|
| 1439 |
+
raise ValueError("unsupported property: "+name)
|
| 1440 |
+
else:
|
| 1441 |
+
if name == "TZID":
|
| 1442 |
+
if parms:
|
| 1443 |
+
raise ValueError(
|
| 1444 |
+
"unsupported TZID parm: "+parms[0])
|
| 1445 |
+
tzid = value
|
| 1446 |
+
elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
|
| 1447 |
+
pass
|
| 1448 |
+
else:
|
| 1449 |
+
raise ValueError("unsupported property: "+name)
|
| 1450 |
+
elif name == "BEGIN" and value == "VTIMEZONE":
|
| 1451 |
+
tzid = None
|
| 1452 |
+
comps = []
|
| 1453 |
+
invtz = True
|
| 1454 |
+
|
| 1455 |
+
def __repr__(self):
|
| 1456 |
+
return "%s(%s)" % (self.__class__.__name__, repr(self._s))
|
| 1457 |
+
|
| 1458 |
+
|
| 1459 |
+
if sys.platform != "win32":
|
| 1460 |
+
TZFILES = ["/etc/localtime", "localtime"]
|
| 1461 |
+
TZPATHS = ["/usr/share/zoneinfo",
|
| 1462 |
+
"/usr/lib/zoneinfo",
|
| 1463 |
+
"/usr/share/lib/zoneinfo",
|
| 1464 |
+
"/etc/zoneinfo"]
|
| 1465 |
+
else:
|
| 1466 |
+
TZFILES = []
|
| 1467 |
+
TZPATHS = []
|
| 1468 |
+
|
| 1469 |
+
|
| 1470 |
+
def __get_gettz():
|
| 1471 |
+
tzlocal_classes = (tzlocal,)
|
| 1472 |
+
if tzwinlocal is not None:
|
| 1473 |
+
tzlocal_classes += (tzwinlocal,)
|
| 1474 |
+
|
| 1475 |
+
class GettzFunc(object):
|
| 1476 |
+
"""
|
| 1477 |
+
Retrieve a time zone object from a string representation
|
| 1478 |
+
|
| 1479 |
+
This function is intended to retrieve the :py:class:`tzinfo` subclass
|
| 1480 |
+
that best represents the time zone that would be used if a POSIX
|
| 1481 |
+
`TZ variable`_ were set to the same value.
|
| 1482 |
+
|
| 1483 |
+
If no argument or an empty string is passed to ``gettz``, local time
|
| 1484 |
+
is returned:
|
| 1485 |
+
|
| 1486 |
+
.. code-block:: python3
|
| 1487 |
+
|
| 1488 |
+
>>> gettz()
|
| 1489 |
+
tzfile('/etc/localtime')
|
| 1490 |
+
|
| 1491 |
+
This function is also the preferred way to map IANA tz database keys
|
| 1492 |
+
to :class:`tzfile` objects:
|
| 1493 |
+
|
| 1494 |
+
.. code-block:: python3
|
| 1495 |
+
|
| 1496 |
+
>>> gettz('Pacific/Kiritimati')
|
| 1497 |
+
tzfile('/usr/share/zoneinfo/Pacific/Kiritimati')
|
| 1498 |
+
|
| 1499 |
+
On Windows, the standard is extended to include the Windows-specific
|
| 1500 |
+
zone names provided by the operating system:
|
| 1501 |
+
|
| 1502 |
+
.. code-block:: python3
|
| 1503 |
+
|
| 1504 |
+
>>> gettz('Egypt Standard Time')
|
| 1505 |
+
tzwin('Egypt Standard Time')
|
| 1506 |
+
|
| 1507 |
+
Passing a GNU ``TZ`` style string time zone specification returns a
|
| 1508 |
+
:class:`tzstr` object:
|
| 1509 |
+
|
| 1510 |
+
.. code-block:: python3
|
| 1511 |
+
|
| 1512 |
+
>>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
|
| 1513 |
+
tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
|
| 1514 |
+
|
| 1515 |
+
:param name:
|
| 1516 |
+
A time zone name (IANA, or, on Windows, Windows keys), location of
|
| 1517 |
+
a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone
|
| 1518 |
+
specifier. An empty string, no argument or ``None`` is interpreted
|
| 1519 |
+
as local time.
|
| 1520 |
+
|
| 1521 |
+
:return:
|
| 1522 |
+
Returns an instance of one of ``dateutil``'s :py:class:`tzinfo`
|
| 1523 |
+
subclasses.
|
| 1524 |
+
|
| 1525 |
+
.. versionchanged:: 2.7.0
|
| 1526 |
+
|
| 1527 |
+
After version 2.7.0, any two calls to ``gettz`` using the same
|
| 1528 |
+
input strings will return the same object:
|
| 1529 |
+
|
| 1530 |
+
.. code-block:: python3
|
| 1531 |
+
|
| 1532 |
+
>>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago')
|
| 1533 |
+
True
|
| 1534 |
+
|
| 1535 |
+
In addition to improving performance, this ensures that
|
| 1536 |
+
`"same zone" semantics`_ are used for datetimes in the same zone.
|
| 1537 |
+
|
| 1538 |
+
|
| 1539 |
+
.. _`TZ variable`:
|
| 1540 |
+
https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
| 1541 |
+
|
| 1542 |
+
.. _`"same zone" semantics`:
|
| 1543 |
+
https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html
|
| 1544 |
+
"""
|
| 1545 |
+
def __init__(self):
|
| 1546 |
+
|
| 1547 |
+
self.__instances = weakref.WeakValueDictionary()
|
| 1548 |
+
self.__strong_cache_size = 8
|
| 1549 |
+
self.__strong_cache = OrderedDict()
|
| 1550 |
+
self._cache_lock = _thread.allocate_lock()
|
| 1551 |
+
|
| 1552 |
+
def __call__(self, name=None):
|
| 1553 |
+
with self._cache_lock:
|
| 1554 |
+
rv = self.__instances.get(name, None)
|
| 1555 |
+
|
| 1556 |
+
if rv is None:
|
| 1557 |
+
rv = self.nocache(name=name)
|
| 1558 |
+
if not (name is None
|
| 1559 |
+
or isinstance(rv, tzlocal_classes)
|
| 1560 |
+
or rv is None):
|
| 1561 |
+
# tzlocal is slightly more complicated than the other
|
| 1562 |
+
# time zone providers because it depends on environment
|
| 1563 |
+
# at construction time, so don't cache that.
|
| 1564 |
+
#
|
| 1565 |
+
# We also cannot store weak references to None, so we
|
| 1566 |
+
# will also not store that.
|
| 1567 |
+
self.__instances[name] = rv
|
| 1568 |
+
else:
|
| 1569 |
+
# No need for strong caching, return immediately
|
| 1570 |
+
return rv
|
| 1571 |
+
|
| 1572 |
+
self.__strong_cache[name] = self.__strong_cache.pop(name, rv)
|
| 1573 |
+
|
| 1574 |
+
if len(self.__strong_cache) > self.__strong_cache_size:
|
| 1575 |
+
self.__strong_cache.popitem(last=False)
|
| 1576 |
+
|
| 1577 |
+
return rv
|
| 1578 |
+
|
| 1579 |
+
def set_cache_size(self, size):
|
| 1580 |
+
with self._cache_lock:
|
| 1581 |
+
self.__strong_cache_size = size
|
| 1582 |
+
while len(self.__strong_cache) > size:
|
| 1583 |
+
self.__strong_cache.popitem(last=False)
|
| 1584 |
+
|
| 1585 |
+
def cache_clear(self):
|
| 1586 |
+
with self._cache_lock:
|
| 1587 |
+
self.__instances = weakref.WeakValueDictionary()
|
| 1588 |
+
self.__strong_cache.clear()
|
| 1589 |
+
|
| 1590 |
+
@staticmethod
|
| 1591 |
+
def nocache(name=None):
|
| 1592 |
+
"""A non-cached version of gettz"""
|
| 1593 |
+
tz = None
|
| 1594 |
+
if not name:
|
| 1595 |
+
try:
|
| 1596 |
+
name = os.environ["TZ"]
|
| 1597 |
+
except KeyError:
|
| 1598 |
+
pass
|
| 1599 |
+
if name is None or name in ("", ":"):
|
| 1600 |
+
for filepath in TZFILES:
|
| 1601 |
+
if not os.path.isabs(filepath):
|
| 1602 |
+
filename = filepath
|
| 1603 |
+
for path in TZPATHS:
|
| 1604 |
+
filepath = os.path.join(path, filename)
|
| 1605 |
+
if os.path.isfile(filepath):
|
| 1606 |
+
break
|
| 1607 |
+
else:
|
| 1608 |
+
continue
|
| 1609 |
+
if os.path.isfile(filepath):
|
| 1610 |
+
try:
|
| 1611 |
+
tz = tzfile(filepath)
|
| 1612 |
+
break
|
| 1613 |
+
except (IOError, OSError, ValueError):
|
| 1614 |
+
pass
|
| 1615 |
+
else:
|
| 1616 |
+
tz = tzlocal()
|
| 1617 |
+
else:
|
| 1618 |
+
try:
|
| 1619 |
+
if name.startswith(":"):
|
| 1620 |
+
name = name[1:]
|
| 1621 |
+
except TypeError as e:
|
| 1622 |
+
if isinstance(name, bytes):
|
| 1623 |
+
new_msg = "gettz argument should be str, not bytes"
|
| 1624 |
+
six.raise_from(TypeError(new_msg), e)
|
| 1625 |
+
else:
|
| 1626 |
+
raise
|
| 1627 |
+
if os.path.isabs(name):
|
| 1628 |
+
if os.path.isfile(name):
|
| 1629 |
+
tz = tzfile(name)
|
| 1630 |
+
else:
|
| 1631 |
+
tz = None
|
| 1632 |
+
else:
|
| 1633 |
+
for path in TZPATHS:
|
| 1634 |
+
filepath = os.path.join(path, name)
|
| 1635 |
+
if not os.path.isfile(filepath):
|
| 1636 |
+
filepath = filepath.replace(' ', '_')
|
| 1637 |
+
if not os.path.isfile(filepath):
|
| 1638 |
+
continue
|
| 1639 |
+
try:
|
| 1640 |
+
tz = tzfile(filepath)
|
| 1641 |
+
break
|
| 1642 |
+
except (IOError, OSError, ValueError):
|
| 1643 |
+
pass
|
| 1644 |
+
else:
|
| 1645 |
+
tz = None
|
| 1646 |
+
if tzwin is not None:
|
| 1647 |
+
try:
|
| 1648 |
+
tz = tzwin(name)
|
| 1649 |
+
except (WindowsError, UnicodeEncodeError):
|
| 1650 |
+
# UnicodeEncodeError is for Python 2.7 compat
|
| 1651 |
+
tz = None
|
| 1652 |
+
|
| 1653 |
+
if not tz:
|
| 1654 |
+
from dateutil.zoneinfo import get_zonefile_instance
|
| 1655 |
+
tz = get_zonefile_instance().get(name)
|
| 1656 |
+
|
| 1657 |
+
if not tz:
|
| 1658 |
+
for c in name:
|
| 1659 |
+
# name is not a tzstr unless it has at least
|
| 1660 |
+
# one offset. For short values of "name", an
|
| 1661 |
+
# explicit for loop seems to be the fastest way
|
| 1662 |
+
# To determine if a string contains a digit
|
| 1663 |
+
if c in "0123456789":
|
| 1664 |
+
try:
|
| 1665 |
+
tz = tzstr(name)
|
| 1666 |
+
except ValueError:
|
| 1667 |
+
pass
|
| 1668 |
+
break
|
| 1669 |
+
else:
|
| 1670 |
+
if name in ("GMT", "UTC"):
|
| 1671 |
+
tz = UTC
|
| 1672 |
+
elif name in time.tzname:
|
| 1673 |
+
tz = tzlocal()
|
| 1674 |
+
return tz
|
| 1675 |
+
|
| 1676 |
+
return GettzFunc()
|
| 1677 |
+
|
| 1678 |
+
|
| 1679 |
+
gettz = __get_gettz()
|
| 1680 |
+
del __get_gettz
|
| 1681 |
+
|
| 1682 |
+
|
| 1683 |
+
def datetime_exists(dt, tz=None):
|
| 1684 |
+
"""
|
| 1685 |
+
Given a datetime and a time zone, determine whether or not a given datetime
|
| 1686 |
+
would fall in a gap.
|
| 1687 |
+
|
| 1688 |
+
:param dt:
|
| 1689 |
+
A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
|
| 1690 |
+
is provided.)
|
| 1691 |
+
|
| 1692 |
+
:param tz:
|
| 1693 |
+
A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
|
| 1694 |
+
``None`` or not provided, the datetime's own time zone will be used.
|
| 1695 |
+
|
| 1696 |
+
:return:
|
| 1697 |
+
Returns a boolean value whether or not the "wall time" exists in
|
| 1698 |
+
``tz``.
|
| 1699 |
+
|
| 1700 |
+
.. versionadded:: 2.7.0
|
| 1701 |
+
"""
|
| 1702 |
+
if tz is None:
|
| 1703 |
+
if dt.tzinfo is None:
|
| 1704 |
+
raise ValueError('Datetime is naive and no time zone provided.')
|
| 1705 |
+
tz = dt.tzinfo
|
| 1706 |
+
|
| 1707 |
+
dt = dt.replace(tzinfo=None)
|
| 1708 |
+
|
| 1709 |
+
# This is essentially a test of whether or not the datetime can survive
|
| 1710 |
+
# a round trip to UTC.
|
| 1711 |
+
dt_rt = dt.replace(tzinfo=tz).astimezone(UTC).astimezone(tz)
|
| 1712 |
+
dt_rt = dt_rt.replace(tzinfo=None)
|
| 1713 |
+
|
| 1714 |
+
return dt == dt_rt
|
| 1715 |
+
|
| 1716 |
+
|
| 1717 |
+
def datetime_ambiguous(dt, tz=None):
|
| 1718 |
+
"""
|
| 1719 |
+
Given a datetime and a time zone, determine whether or not a given datetime
|
| 1720 |
+
is ambiguous (i.e if there are two times differentiated only by their DST
|
| 1721 |
+
status).
|
| 1722 |
+
|
| 1723 |
+
:param dt:
|
| 1724 |
+
A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
|
| 1725 |
+
is provided.)
|
| 1726 |
+
|
| 1727 |
+
:param tz:
|
| 1728 |
+
A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
|
| 1729 |
+
``None`` or not provided, the datetime's own time zone will be used.
|
| 1730 |
+
|
| 1731 |
+
:return:
|
| 1732 |
+
Returns a boolean value whether or not the "wall time" is ambiguous in
|
| 1733 |
+
``tz``.
|
| 1734 |
+
|
| 1735 |
+
.. versionadded:: 2.6.0
|
| 1736 |
+
"""
|
| 1737 |
+
if tz is None:
|
| 1738 |
+
if dt.tzinfo is None:
|
| 1739 |
+
raise ValueError('Datetime is naive and no time zone provided.')
|
| 1740 |
+
|
| 1741 |
+
tz = dt.tzinfo
|
| 1742 |
+
|
| 1743 |
+
# If a time zone defines its own "is_ambiguous" function, we'll use that.
|
| 1744 |
+
is_ambiguous_fn = getattr(tz, 'is_ambiguous', None)
|
| 1745 |
+
if is_ambiguous_fn is not None:
|
| 1746 |
+
try:
|
| 1747 |
+
return tz.is_ambiguous(dt)
|
| 1748 |
+
except Exception:
|
| 1749 |
+
pass
|
| 1750 |
+
|
| 1751 |
+
# If it doesn't come out and tell us it's ambiguous, we'll just check if
|
| 1752 |
+
# the fold attribute has any effect on this particular date and time.
|
| 1753 |
+
dt = dt.replace(tzinfo=tz)
|
| 1754 |
+
wall_0 = enfold(dt, fold=0)
|
| 1755 |
+
wall_1 = enfold(dt, fold=1)
|
| 1756 |
+
|
| 1757 |
+
same_offset = wall_0.utcoffset() == wall_1.utcoffset()
|
| 1758 |
+
same_dst = wall_0.dst() == wall_1.dst()
|
| 1759 |
+
|
| 1760 |
+
return not (same_offset and same_dst)
|
| 1761 |
+
|
| 1762 |
+
|
| 1763 |
+
def resolve_imaginary(dt):
|
| 1764 |
+
"""
|
| 1765 |
+
Given a datetime that may be imaginary, return an existing datetime.
|
| 1766 |
+
|
| 1767 |
+
This function assumes that an imaginary datetime represents what the
|
| 1768 |
+
wall time would be in a zone had the offset transition not occurred, so
|
| 1769 |
+
it will always fall forward by the transition's change in offset.
|
| 1770 |
+
|
| 1771 |
+
.. doctest::
|
| 1772 |
+
|
| 1773 |
+
>>> from dateutil import tz
|
| 1774 |
+
>>> from datetime import datetime
|
| 1775 |
+
>>> NYC = tz.gettz('America/New_York')
|
| 1776 |
+
>>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
|
| 1777 |
+
2017-03-12 03:30:00-04:00
|
| 1778 |
+
|
| 1779 |
+
>>> KIR = tz.gettz('Pacific/Kiritimati')
|
| 1780 |
+
>>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR)))
|
| 1781 |
+
1995-01-02 12:30:00+14:00
|
| 1782 |
+
|
| 1783 |
+
As a note, :func:`datetime.astimezone` is guaranteed to produce a valid,
|
| 1784 |
+
existing datetime, so a round-trip to and from UTC is sufficient to get
|
| 1785 |
+
an extant datetime, however, this generally "falls back" to an earlier time
|
| 1786 |
+
rather than falling forward to the STD side (though no guarantees are made
|
| 1787 |
+
about this behavior).
|
| 1788 |
+
|
| 1789 |
+
:param dt:
|
| 1790 |
+
A :class:`datetime.datetime` which may or may not exist.
|
| 1791 |
+
|
| 1792 |
+
:return:
|
| 1793 |
+
Returns an existing :class:`datetime.datetime`. If ``dt`` was not
|
| 1794 |
+
imaginary, the datetime returned is guaranteed to be the same object
|
| 1795 |
+
passed to the function.
|
| 1796 |
+
|
| 1797 |
+
.. versionadded:: 2.7.0
|
| 1798 |
+
"""
|
| 1799 |
+
if dt.tzinfo is not None and not datetime_exists(dt):
|
| 1800 |
+
|
| 1801 |
+
curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset()
|
| 1802 |
+
old_offset = (dt - datetime.timedelta(hours=24)).utcoffset()
|
| 1803 |
+
|
| 1804 |
+
dt += curr_offset - old_offset
|
| 1805 |
+
|
| 1806 |
+
return dt
|
| 1807 |
+
|
| 1808 |
+
|
| 1809 |
+
def _datetime_to_timestamp(dt):
|
| 1810 |
+
"""
|
| 1811 |
+
Convert a :class:`datetime.datetime` object to an epoch timestamp in
|
| 1812 |
+
seconds since January 1, 1970, ignoring the time zone.
|
| 1813 |
+
"""
|
| 1814 |
+
return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
|
| 1815 |
+
|
| 1816 |
+
|
| 1817 |
+
if sys.version_info >= (3, 6):
|
| 1818 |
+
def _get_supported_offset(second_offset):
|
| 1819 |
+
return second_offset
|
| 1820 |
+
else:
|
| 1821 |
+
def _get_supported_offset(second_offset):
|
| 1822 |
+
# For python pre-3.6, round to full-minutes if that's not the case.
|
| 1823 |
+
# Python's datetime doesn't accept sub-minute timezones. Check
|
| 1824 |
+
# http://python.org/sf/1447945 or https://bugs.python.org/issue5288
|
| 1825 |
+
# for some information.
|
| 1826 |
+
old_offset = second_offset
|
| 1827 |
+
calculated_offset = 60 * ((second_offset + 30) // 60)
|
| 1828 |
+
return calculated_offset
|
| 1829 |
+
|
| 1830 |
+
|
| 1831 |
+
try:
|
| 1832 |
+
# Python 3.7 feature
|
| 1833 |
+
from contextlib import nullcontext as _nullcontext
|
| 1834 |
+
except ImportError:
|
| 1835 |
+
class _nullcontext(object):
|
| 1836 |
+
"""
|
| 1837 |
+
Class for wrapping contexts so that they are passed through in a
|
| 1838 |
+
with statement.
|
| 1839 |
+
"""
|
| 1840 |
+
def __init__(self, context):
|
| 1841 |
+
self.context = context
|
| 1842 |
+
|
| 1843 |
+
def __enter__(self):
|
| 1844 |
+
return self.context
|
| 1845 |
+
|
| 1846 |
+
def __exit__(*args, **kwargs):
|
| 1847 |
+
pass
|
| 1848 |
+
|
| 1849 |
+
# vim:ts=4:sw=4:et
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/tz/win.py
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
This module provides an interface to the native time zone data on Windows,
|
| 4 |
+
including :py:class:`datetime.tzinfo` implementations.
|
| 5 |
+
|
| 6 |
+
Attempting to import this module on a non-Windows platform will raise an
|
| 7 |
+
:py:obj:`ImportError`.
|
| 8 |
+
"""
|
| 9 |
+
# This code was originally contributed by Jeffrey Harris.
|
| 10 |
+
import datetime
|
| 11 |
+
import struct
|
| 12 |
+
|
| 13 |
+
from six.moves import winreg
|
| 14 |
+
from six import text_type
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
import ctypes
|
| 18 |
+
from ctypes import wintypes
|
| 19 |
+
except ValueError:
|
| 20 |
+
# ValueError is raised on non-Windows systems for some horrible reason.
|
| 21 |
+
raise ImportError("Running tzwin on non-Windows system")
|
| 22 |
+
|
| 23 |
+
from ._common import tzrangebase
|
| 24 |
+
|
| 25 |
+
__all__ = ["tzwin", "tzwinlocal", "tzres"]
|
| 26 |
+
|
| 27 |
+
ONEWEEK = datetime.timedelta(7)
|
| 28 |
+
|
| 29 |
+
TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
|
| 30 |
+
TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
|
| 31 |
+
TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _settzkeyname():
|
| 35 |
+
handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
| 36 |
+
try:
|
| 37 |
+
winreg.OpenKey(handle, TZKEYNAMENT).Close()
|
| 38 |
+
TZKEYNAME = TZKEYNAMENT
|
| 39 |
+
except WindowsError:
|
| 40 |
+
TZKEYNAME = TZKEYNAME9X
|
| 41 |
+
handle.Close()
|
| 42 |
+
return TZKEYNAME
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
TZKEYNAME = _settzkeyname()
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class tzres(object):
|
| 49 |
+
"""
|
| 50 |
+
Class for accessing ``tzres.dll``, which contains timezone name related
|
| 51 |
+
resources.
|
| 52 |
+
|
| 53 |
+
.. versionadded:: 2.5.0
|
| 54 |
+
"""
|
| 55 |
+
p_wchar = ctypes.POINTER(wintypes.WCHAR) # Pointer to a wide char
|
| 56 |
+
|
| 57 |
+
def __init__(self, tzres_loc='tzres.dll'):
|
| 58 |
+
# Load the user32 DLL so we can load strings from tzres
|
| 59 |
+
user32 = ctypes.WinDLL('user32')
|
| 60 |
+
|
| 61 |
+
# Specify the LoadStringW function
|
| 62 |
+
user32.LoadStringW.argtypes = (wintypes.HINSTANCE,
|
| 63 |
+
wintypes.UINT,
|
| 64 |
+
wintypes.LPWSTR,
|
| 65 |
+
ctypes.c_int)
|
| 66 |
+
|
| 67 |
+
self.LoadStringW = user32.LoadStringW
|
| 68 |
+
self._tzres = ctypes.WinDLL(tzres_loc)
|
| 69 |
+
self.tzres_loc = tzres_loc
|
| 70 |
+
|
| 71 |
+
def load_name(self, offset):
|
| 72 |
+
"""
|
| 73 |
+
Load a timezone name from a DLL offset (integer).
|
| 74 |
+
|
| 75 |
+
>>> from dateutil.tzwin import tzres
|
| 76 |
+
>>> tzr = tzres()
|
| 77 |
+
>>> print(tzr.load_name(112))
|
| 78 |
+
'Eastern Standard Time'
|
| 79 |
+
|
| 80 |
+
:param offset:
|
| 81 |
+
A positive integer value referring to a string from the tzres dll.
|
| 82 |
+
|
| 83 |
+
.. note::
|
| 84 |
+
|
| 85 |
+
Offsets found in the registry are generally of the form
|
| 86 |
+
``@tzres.dll,-114``. The offset in this case is 114, not -114.
|
| 87 |
+
|
| 88 |
+
"""
|
| 89 |
+
resource = self.p_wchar()
|
| 90 |
+
lpBuffer = ctypes.cast(ctypes.byref(resource), wintypes.LPWSTR)
|
| 91 |
+
nchar = self.LoadStringW(self._tzres._handle, offset, lpBuffer, 0)
|
| 92 |
+
return resource[:nchar]
|
| 93 |
+
|
| 94 |
+
def name_from_string(self, tzname_str):
|
| 95 |
+
"""
|
| 96 |
+
Parse strings as returned from the Windows registry into the time zone
|
| 97 |
+
name as defined in the registry.
|
| 98 |
+
|
| 99 |
+
>>> from dateutil.tzwin import tzres
|
| 100 |
+
>>> tzr = tzres()
|
| 101 |
+
>>> print(tzr.name_from_string('@tzres.dll,-251'))
|
| 102 |
+
'Dateline Daylight Time'
|
| 103 |
+
>>> print(tzr.name_from_string('Eastern Standard Time'))
|
| 104 |
+
'Eastern Standard Time'
|
| 105 |
+
|
| 106 |
+
:param tzname_str:
|
| 107 |
+
A timezone name string as returned from a Windows registry key.
|
| 108 |
+
|
| 109 |
+
:return:
|
| 110 |
+
Returns the localized timezone string from tzres.dll if the string
|
| 111 |
+
is of the form `@tzres.dll,-offset`, else returns the input string.
|
| 112 |
+
"""
|
| 113 |
+
if not tzname_str.startswith('@'):
|
| 114 |
+
return tzname_str
|
| 115 |
+
|
| 116 |
+
name_splt = tzname_str.split(',-')
|
| 117 |
+
try:
|
| 118 |
+
offset = int(name_splt[1])
|
| 119 |
+
except:
|
| 120 |
+
raise ValueError("Malformed timezone string.")
|
| 121 |
+
|
| 122 |
+
return self.load_name(offset)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
class tzwinbase(tzrangebase):
|
| 126 |
+
"""tzinfo class based on win32's timezones available in the registry."""
|
| 127 |
+
def __init__(self):
|
| 128 |
+
raise NotImplementedError('tzwinbase is an abstract base class')
|
| 129 |
+
|
| 130 |
+
def __eq__(self, other):
|
| 131 |
+
# Compare on all relevant dimensions, including name.
|
| 132 |
+
if not isinstance(other, tzwinbase):
|
| 133 |
+
return NotImplemented
|
| 134 |
+
|
| 135 |
+
return (self._std_offset == other._std_offset and
|
| 136 |
+
self._dst_offset == other._dst_offset and
|
| 137 |
+
self._stddayofweek == other._stddayofweek and
|
| 138 |
+
self._dstdayofweek == other._dstdayofweek and
|
| 139 |
+
self._stdweeknumber == other._stdweeknumber and
|
| 140 |
+
self._dstweeknumber == other._dstweeknumber and
|
| 141 |
+
self._stdhour == other._stdhour and
|
| 142 |
+
self._dsthour == other._dsthour and
|
| 143 |
+
self._stdminute == other._stdminute and
|
| 144 |
+
self._dstminute == other._dstminute and
|
| 145 |
+
self._std_abbr == other._std_abbr and
|
| 146 |
+
self._dst_abbr == other._dst_abbr)
|
| 147 |
+
|
| 148 |
+
@staticmethod
|
| 149 |
+
def list():
|
| 150 |
+
"""Return a list of all time zones known to the system."""
|
| 151 |
+
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
| 152 |
+
with winreg.OpenKey(handle, TZKEYNAME) as tzkey:
|
| 153 |
+
result = [winreg.EnumKey(tzkey, i)
|
| 154 |
+
for i in range(winreg.QueryInfoKey(tzkey)[0])]
|
| 155 |
+
return result
|
| 156 |
+
|
| 157 |
+
def display(self):
|
| 158 |
+
"""
|
| 159 |
+
Return the display name of the time zone.
|
| 160 |
+
"""
|
| 161 |
+
return self._display
|
| 162 |
+
|
| 163 |
+
def transitions(self, year):
|
| 164 |
+
"""
|
| 165 |
+
For a given year, get the DST on and off transition times, expressed
|
| 166 |
+
always on the standard time side. For zones with no transitions, this
|
| 167 |
+
function returns ``None``.
|
| 168 |
+
|
| 169 |
+
:param year:
|
| 170 |
+
The year whose transitions you would like to query.
|
| 171 |
+
|
| 172 |
+
:return:
|
| 173 |
+
Returns a :class:`tuple` of :class:`datetime.datetime` objects,
|
| 174 |
+
``(dston, dstoff)`` for zones with an annual DST transition, or
|
| 175 |
+
``None`` for fixed offset zones.
|
| 176 |
+
"""
|
| 177 |
+
|
| 178 |
+
if not self.hasdst:
|
| 179 |
+
return None
|
| 180 |
+
|
| 181 |
+
dston = picknthweekday(year, self._dstmonth, self._dstdayofweek,
|
| 182 |
+
self._dsthour, self._dstminute,
|
| 183 |
+
self._dstweeknumber)
|
| 184 |
+
|
| 185 |
+
dstoff = picknthweekday(year, self._stdmonth, self._stddayofweek,
|
| 186 |
+
self._stdhour, self._stdminute,
|
| 187 |
+
self._stdweeknumber)
|
| 188 |
+
|
| 189 |
+
# Ambiguous dates default to the STD side
|
| 190 |
+
dstoff -= self._dst_base_offset
|
| 191 |
+
|
| 192 |
+
return dston, dstoff
|
| 193 |
+
|
| 194 |
+
def _get_hasdst(self):
|
| 195 |
+
return self._dstmonth != 0
|
| 196 |
+
|
| 197 |
+
@property
|
| 198 |
+
def _dst_base_offset(self):
|
| 199 |
+
return self._dst_base_offset_
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
class tzwin(tzwinbase):
|
| 203 |
+
"""
|
| 204 |
+
Time zone object created from the zone info in the Windows registry
|
| 205 |
+
|
| 206 |
+
These are similar to :py:class:`dateutil.tz.tzrange` objects in that
|
| 207 |
+
the time zone data is provided in the format of a single offset rule
|
| 208 |
+
for either 0 or 2 time zone transitions per year.
|
| 209 |
+
|
| 210 |
+
:param: name
|
| 211 |
+
The name of a Windows time zone key, e.g. "Eastern Standard Time".
|
| 212 |
+
The full list of keys can be retrieved with :func:`tzwin.list`.
|
| 213 |
+
"""
|
| 214 |
+
|
| 215 |
+
def __init__(self, name):
|
| 216 |
+
self._name = name
|
| 217 |
+
|
| 218 |
+
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
| 219 |
+
tzkeyname = text_type("{kn}\\{name}").format(kn=TZKEYNAME, name=name)
|
| 220 |
+
with winreg.OpenKey(handle, tzkeyname) as tzkey:
|
| 221 |
+
keydict = valuestodict(tzkey)
|
| 222 |
+
|
| 223 |
+
self._std_abbr = keydict["Std"]
|
| 224 |
+
self._dst_abbr = keydict["Dlt"]
|
| 225 |
+
|
| 226 |
+
self._display = keydict["Display"]
|
| 227 |
+
|
| 228 |
+
# See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
|
| 229 |
+
tup = struct.unpack("=3l16h", keydict["TZI"])
|
| 230 |
+
stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
|
| 231 |
+
dstoffset = stdoffset-tup[2] # + DaylightBias * -1
|
| 232 |
+
self._std_offset = datetime.timedelta(minutes=stdoffset)
|
| 233 |
+
self._dst_offset = datetime.timedelta(minutes=dstoffset)
|
| 234 |
+
|
| 235 |
+
# for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
|
| 236 |
+
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
|
| 237 |
+
(self._stdmonth,
|
| 238 |
+
self._stddayofweek, # Sunday = 0
|
| 239 |
+
self._stdweeknumber, # Last = 5
|
| 240 |
+
self._stdhour,
|
| 241 |
+
self._stdminute) = tup[4:9]
|
| 242 |
+
|
| 243 |
+
(self._dstmonth,
|
| 244 |
+
self._dstdayofweek, # Sunday = 0
|
| 245 |
+
self._dstweeknumber, # Last = 5
|
| 246 |
+
self._dsthour,
|
| 247 |
+
self._dstminute) = tup[12:17]
|
| 248 |
+
|
| 249 |
+
self._dst_base_offset_ = self._dst_offset - self._std_offset
|
| 250 |
+
self.hasdst = self._get_hasdst()
|
| 251 |
+
|
| 252 |
+
def __repr__(self):
|
| 253 |
+
return "tzwin(%s)" % repr(self._name)
|
| 254 |
+
|
| 255 |
+
def __reduce__(self):
|
| 256 |
+
return (self.__class__, (self._name,))
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
class tzwinlocal(tzwinbase):
|
| 260 |
+
"""
|
| 261 |
+
Class representing the local time zone information in the Windows registry
|
| 262 |
+
|
| 263 |
+
While :class:`dateutil.tz.tzlocal` makes system calls (via the :mod:`time`
|
| 264 |
+
module) to retrieve time zone information, ``tzwinlocal`` retrieves the
|
| 265 |
+
rules directly from the Windows registry and creates an object like
|
| 266 |
+
:class:`dateutil.tz.tzwin`.
|
| 267 |
+
|
| 268 |
+
Because Windows does not have an equivalent of :func:`time.tzset`, on
|
| 269 |
+
Windows, :class:`dateutil.tz.tzlocal` instances will always reflect the
|
| 270 |
+
time zone settings *at the time that the process was started*, meaning
|
| 271 |
+
changes to the machine's time zone settings during the run of a program
|
| 272 |
+
on Windows will **not** be reflected by :class:`dateutil.tz.tzlocal`.
|
| 273 |
+
Because ``tzwinlocal`` reads the registry directly, it is unaffected by
|
| 274 |
+
this issue.
|
| 275 |
+
"""
|
| 276 |
+
def __init__(self):
|
| 277 |
+
with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
|
| 278 |
+
with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
|
| 279 |
+
keydict = valuestodict(tzlocalkey)
|
| 280 |
+
|
| 281 |
+
self._std_abbr = keydict["StandardName"]
|
| 282 |
+
self._dst_abbr = keydict["DaylightName"]
|
| 283 |
+
|
| 284 |
+
try:
|
| 285 |
+
tzkeyname = text_type('{kn}\\{sn}').format(kn=TZKEYNAME,
|
| 286 |
+
sn=self._std_abbr)
|
| 287 |
+
with winreg.OpenKey(handle, tzkeyname) as tzkey:
|
| 288 |
+
_keydict = valuestodict(tzkey)
|
| 289 |
+
self._display = _keydict["Display"]
|
| 290 |
+
except OSError:
|
| 291 |
+
self._display = None
|
| 292 |
+
|
| 293 |
+
stdoffset = -keydict["Bias"]-keydict["StandardBias"]
|
| 294 |
+
dstoffset = stdoffset-keydict["DaylightBias"]
|
| 295 |
+
|
| 296 |
+
self._std_offset = datetime.timedelta(minutes=stdoffset)
|
| 297 |
+
self._dst_offset = datetime.timedelta(minutes=dstoffset)
|
| 298 |
+
|
| 299 |
+
# For reasons unclear, in this particular key, the day of week has been
|
| 300 |
+
# moved to the END of the SYSTEMTIME structure.
|
| 301 |
+
tup = struct.unpack("=8h", keydict["StandardStart"])
|
| 302 |
+
|
| 303 |
+
(self._stdmonth,
|
| 304 |
+
self._stdweeknumber, # Last = 5
|
| 305 |
+
self._stdhour,
|
| 306 |
+
self._stdminute) = tup[1:5]
|
| 307 |
+
|
| 308 |
+
self._stddayofweek = tup[7]
|
| 309 |
+
|
| 310 |
+
tup = struct.unpack("=8h", keydict["DaylightStart"])
|
| 311 |
+
|
| 312 |
+
(self._dstmonth,
|
| 313 |
+
self._dstweeknumber, # Last = 5
|
| 314 |
+
self._dsthour,
|
| 315 |
+
self._dstminute) = tup[1:5]
|
| 316 |
+
|
| 317 |
+
self._dstdayofweek = tup[7]
|
| 318 |
+
|
| 319 |
+
self._dst_base_offset_ = self._dst_offset - self._std_offset
|
| 320 |
+
self.hasdst = self._get_hasdst()
|
| 321 |
+
|
| 322 |
+
def __repr__(self):
|
| 323 |
+
return "tzwinlocal()"
|
| 324 |
+
|
| 325 |
+
def __str__(self):
|
| 326 |
+
# str will return the standard name, not the daylight name.
|
| 327 |
+
return "tzwinlocal(%s)" % repr(self._std_abbr)
|
| 328 |
+
|
| 329 |
+
def __reduce__(self):
|
| 330 |
+
return (self.__class__, ())
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
|
| 334 |
+
""" dayofweek == 0 means Sunday, whichweek 5 means last instance """
|
| 335 |
+
first = datetime.datetime(year, month, 1, hour, minute)
|
| 336 |
+
|
| 337 |
+
# This will work if dayofweek is ISO weekday (1-7) or Microsoft-style (0-6),
|
| 338 |
+
# Because 7 % 7 = 0
|
| 339 |
+
weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7) + 1)
|
| 340 |
+
wd = weekdayone + ((whichweek - 1) * ONEWEEK)
|
| 341 |
+
if (wd.month != month):
|
| 342 |
+
wd -= ONEWEEK
|
| 343 |
+
|
| 344 |
+
return wd
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def valuestodict(key):
|
| 348 |
+
"""Convert a registry key's values to a dictionary."""
|
| 349 |
+
dout = {}
|
| 350 |
+
size = winreg.QueryInfoKey(key)[1]
|
| 351 |
+
tz_res = None
|
| 352 |
+
|
| 353 |
+
for i in range(size):
|
| 354 |
+
key_name, value, dtype = winreg.EnumValue(key, i)
|
| 355 |
+
if dtype == winreg.REG_DWORD or dtype == winreg.REG_DWORD_LITTLE_ENDIAN:
|
| 356 |
+
# If it's a DWORD (32-bit integer), it's stored as unsigned - convert
|
| 357 |
+
# that to a proper signed integer
|
| 358 |
+
if value & (1 << 31):
|
| 359 |
+
value = value - (1 << 32)
|
| 360 |
+
elif dtype == winreg.REG_SZ:
|
| 361 |
+
# If it's a reference to the tzres DLL, load the actual string
|
| 362 |
+
if value.startswith('@tzres'):
|
| 363 |
+
tz_res = tz_res or tzres()
|
| 364 |
+
value = tz_res.name_from_string(value)
|
| 365 |
+
|
| 366 |
+
value = value.rstrip('\x00') # Remove trailing nulls
|
| 367 |
+
|
| 368 |
+
dout[key_name] = value
|
| 369 |
+
|
| 370 |
+
return dout
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/dateutil/zoneinfo/__init__.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
import warnings
|
| 3 |
+
import json
|
| 4 |
+
|
| 5 |
+
from tarfile import TarFile
|
| 6 |
+
from pkgutil import get_data
|
| 7 |
+
from io import BytesIO
|
| 8 |
+
|
| 9 |
+
from dateutil.tz import tzfile as _tzfile
|
| 10 |
+
|
| 11 |
+
__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
|
| 12 |
+
|
| 13 |
+
ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
|
| 14 |
+
METADATA_FN = 'METADATA'
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class tzfile(_tzfile):
|
| 18 |
+
def __reduce__(self):
|
| 19 |
+
return (gettz, (self._filename,))
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def getzoneinfofile_stream():
|
| 23 |
+
try:
|
| 24 |
+
return BytesIO(get_data(__name__, ZONEFILENAME))
|
| 25 |
+
except IOError as e: # TODO switch to FileNotFoundError?
|
| 26 |
+
warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror))
|
| 27 |
+
return None
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class ZoneInfoFile(object):
|
| 31 |
+
def __init__(self, zonefile_stream=None):
|
| 32 |
+
if zonefile_stream is not None:
|
| 33 |
+
with TarFile.open(fileobj=zonefile_stream) as tf:
|
| 34 |
+
self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
|
| 35 |
+
for zf in tf.getmembers()
|
| 36 |
+
if zf.isfile() and zf.name != METADATA_FN}
|
| 37 |
+
# deal with links: They'll point to their parent object. Less
|
| 38 |
+
# waste of memory
|
| 39 |
+
links = {zl.name: self.zones[zl.linkname]
|
| 40 |
+
for zl in tf.getmembers() if
|
| 41 |
+
zl.islnk() or zl.issym()}
|
| 42 |
+
self.zones.update(links)
|
| 43 |
+
try:
|
| 44 |
+
metadata_json = tf.extractfile(tf.getmember(METADATA_FN))
|
| 45 |
+
metadata_str = metadata_json.read().decode('UTF-8')
|
| 46 |
+
self.metadata = json.loads(metadata_str)
|
| 47 |
+
except KeyError:
|
| 48 |
+
# no metadata in tar file
|
| 49 |
+
self.metadata = None
|
| 50 |
+
else:
|
| 51 |
+
self.zones = {}
|
| 52 |
+
self.metadata = None
|
| 53 |
+
|
| 54 |
+
def get(self, name, default=None):
|
| 55 |
+
"""
|
| 56 |
+
Wrapper for :func:`ZoneInfoFile.zones.get`. This is a convenience method
|
| 57 |
+
for retrieving zones from the zone dictionary.
|
| 58 |
+
|
| 59 |
+
:param name:
|
| 60 |
+
The name of the zone to retrieve. (Generally IANA zone names)
|
| 61 |
+
|
| 62 |
+
:param default:
|
| 63 |
+
The value to return in the event of a missing key.
|
| 64 |
+
|
| 65 |
+
.. versionadded:: 2.6.0
|
| 66 |
+
|
| 67 |
+
"""
|
| 68 |
+
return self.zones.get(name, default)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# The current API has gettz as a module function, although in fact it taps into
|
| 72 |
+
# a stateful class. So as a workaround for now, without changing the API, we
|
| 73 |
+
# will create a new "global" class instance the first time a user requests a
|
| 74 |
+
# timezone. Ugly, but adheres to the api.
|
| 75 |
+
#
|
| 76 |
+
# TODO: Remove after deprecation period.
|
| 77 |
+
_CLASS_ZONE_INSTANCE = []
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def get_zonefile_instance(new_instance=False):
|
| 81 |
+
"""
|
| 82 |
+
This is a convenience function which provides a :class:`ZoneInfoFile`
|
| 83 |
+
instance using the data provided by the ``dateutil`` package. By default, it
|
| 84 |
+
caches a single instance of the ZoneInfoFile object and returns that.
|
| 85 |
+
|
| 86 |
+
:param new_instance:
|
| 87 |
+
If ``True``, a new instance of :class:`ZoneInfoFile` is instantiated and
|
| 88 |
+
used as the cached instance for the next call. Otherwise, new instances
|
| 89 |
+
are created only as necessary.
|
| 90 |
+
|
| 91 |
+
:return:
|
| 92 |
+
Returns a :class:`ZoneInfoFile` object.
|
| 93 |
+
|
| 94 |
+
.. versionadded:: 2.6
|
| 95 |
+
"""
|
| 96 |
+
if new_instance:
|
| 97 |
+
zif = None
|
| 98 |
+
else:
|
| 99 |
+
zif = getattr(get_zonefile_instance, '_cached_instance', None)
|
| 100 |
+
|
| 101 |
+
if zif is None:
|
| 102 |
+
zif = ZoneInfoFile(getzoneinfofile_stream())
|
| 103 |
+
|
| 104 |
+
get_zonefile_instance._cached_instance = zif
|
| 105 |
+
|
| 106 |
+
return zif
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def gettz(name):
|
| 110 |
+
"""
|
| 111 |
+
This retrieves a time zone from the local zoneinfo tarball that is packaged
|
| 112 |
+
with dateutil.
|
| 113 |
+
|
| 114 |
+
:param name:
|
| 115 |
+
An IANA-style time zone name, as found in the zoneinfo file.
|
| 116 |
+
|
| 117 |
+
:return:
|
| 118 |
+
Returns a :class:`dateutil.tz.tzfile` time zone object.
|
| 119 |
+
|
| 120 |
+
.. warning::
|
| 121 |
+
It is generally inadvisable to use this function, and it is only
|
| 122 |
+
provided for API compatibility with earlier versions. This is *not*
|
| 123 |
+
equivalent to ``dateutil.tz.gettz()``, which selects an appropriate
|
| 124 |
+
time zone based on the inputs, favoring system zoneinfo. This is ONLY
|
| 125 |
+
for accessing the dateutil-specific zoneinfo (which may be out of
|
| 126 |
+
date compared to the system zoneinfo).
|
| 127 |
+
|
| 128 |
+
.. deprecated:: 2.6
|
| 129 |
+
If you need to use a specific zoneinfofile over the system zoneinfo,
|
| 130 |
+
instantiate a :class:`dateutil.zoneinfo.ZoneInfoFile` object and call
|
| 131 |
+
:func:`dateutil.zoneinfo.ZoneInfoFile.get(name)` instead.
|
| 132 |
+
|
| 133 |
+
Use :func:`get_zonefile_instance` to retrieve an instance of the
|
| 134 |
+
dateutil-provided zoneinfo.
|
| 135 |
+
"""
|
| 136 |
+
warnings.warn("zoneinfo.gettz() will be removed in future versions, "
|
| 137 |
+
"to use the dateutil-provided zoneinfo files, instantiate a "
|
| 138 |
+
"ZoneInfoFile object and use ZoneInfoFile.zones.get() "
|
| 139 |
+
"instead. See the documentation for details.",
|
| 140 |
+
DeprecationWarning)
|
| 141 |
+
|
| 142 |
+
if len(_CLASS_ZONE_INSTANCE) == 0:
|
| 143 |
+
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
| 144 |
+
return _CLASS_ZONE_INSTANCE[0].zones.get(name)
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def gettz_db_metadata():
|
| 148 |
+
""" Get the zonefile metadata
|
| 149 |
+
|
| 150 |
+
See `zonefile_metadata`_
|
| 151 |
+
|
| 152 |
+
:returns:
|
| 153 |
+
A dictionary with the database metadata
|
| 154 |
+
|
| 155 |
+
.. deprecated:: 2.6
|
| 156 |
+
See deprecation warning in :func:`zoneinfo.gettz`. To get metadata,
|
| 157 |
+
query the attribute ``zoneinfo.ZoneInfoFile.metadata``.
|
| 158 |
+
"""
|
| 159 |
+
warnings.warn("zoneinfo.gettz_db_metadata() will be removed in future "
|
| 160 |
+
"versions, to use the dateutil-provided zoneinfo files, "
|
| 161 |
+
"ZoneInfoFile object and query the 'metadata' attribute "
|
| 162 |
+
"instead. See the documentation for details.",
|
| 163 |
+
DeprecationWarning)
|
| 164 |
+
|
| 165 |
+
if len(_CLASS_ZONE_INSTANCE) == 0:
|
| 166 |
+
_CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
|
| 167 |
+
return _CLASS_ZONE_INSTANCE[0].metadata
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (1.51 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/config.cpython-312.pyc
ADDED
|
Binary file (7.56 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/hub.cpython-312.pyc
ADDED
|
Binary file (4.94 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/info.cpython-312.pyc
ADDED
|
Binary file (7.37 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/inspect.cpython-312.pyc
ADDED
|
Binary file (4.92 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/loading.cpython-312.pyc
ADDED
|
Binary file (37.1 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/module.cpython-312.pyc
ADDED
|
Binary file (55.4 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/naming.cpython-312.pyc
ADDED
|
Binary file (3.74 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/saving.cpython-312.pyc
ADDED
|
Binary file (3.58 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/__pycache__/visualization.cpython-312.pyc
ADDED
|
Binary file (11.9 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__init__.py
ADDED
|
File without changes
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (223 Bytes). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/__pycache__/evaluate_cli.cpython-312.pyc
ADDED
|
Binary file (5.61 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/commands/evaluate_cli.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import os
|
| 3 |
+
import subprocess
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
from cookiecutter.main import cookiecutter
|
| 7 |
+
from huggingface_hub import HfApi, Repository, create_repo
|
| 8 |
+
|
| 9 |
+
from evaluate.utils.logging import get_logger
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
logger = get_logger(__name__)
|
| 13 |
+
|
| 14 |
+
INSTRUCTIONS = """\
|
| 15 |
+
A new repository for your module "{module_name}" of type "{module_type}" has been created at {output_dir} and pushed to the Hugging Face Hub: {repo_url}.
|
| 16 |
+
|
| 17 |
+
Here are the next steps:
|
| 18 |
+
- implement the module logic in {module_slug}/{module_slug}.py
|
| 19 |
+
- document your module in {module_slug}/README.md
|
| 20 |
+
- add test cases for your module in {module_slug}/tests.py
|
| 21 |
+
- if your module has any dependencies update them in {module_slug}/requirements.txt
|
| 22 |
+
|
| 23 |
+
You can test your module's widget locally by running:
|
| 24 |
+
|
| 25 |
+
```
|
| 26 |
+
python {output_dir}/{module_slug}/app.py
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
When you are happy with your changes you can push your changes with the following commands to the Hugging Face Hub:
|
| 30 |
+
|
| 31 |
+
```
|
| 32 |
+
cd {output_dir}/{module_slug}
|
| 33 |
+
git add .
|
| 34 |
+
git commit -m "Updating module"
|
| 35 |
+
git push
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
You should then see the update widget on the Hugging Face Hub: {repo_url}
|
| 39 |
+
And you can load your module in Python with the following code:
|
| 40 |
+
|
| 41 |
+
```
|
| 42 |
+
from evaluate import load
|
| 43 |
+
module = load("{namespace}/{module_slug}")
|
| 44 |
+
```
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def main():
|
| 49 |
+
parser = argparse.ArgumentParser("HuggingFace Evaluate CLI tool", usage="evaluate-cli <command> [<args>]")
|
| 50 |
+
subparsers = parser.add_subparsers()
|
| 51 |
+
parser_create = subparsers.add_parser("create", help="Create new evaluation module.")
|
| 52 |
+
parser_create.add_argument(
|
| 53 |
+
"module_name", type=str, help='Pretty name of new evaluation module, e.g. "Recall" or "Exact Match".'
|
| 54 |
+
)
|
| 55 |
+
parser_create.add_argument(
|
| 56 |
+
"--module_type",
|
| 57 |
+
default="metric",
|
| 58 |
+
type=str,
|
| 59 |
+
help="Type of module, has to be one of [metric|comparison|measurement].",
|
| 60 |
+
)
|
| 61 |
+
parser_create.add_argument(
|
| 62 |
+
"--dataset_name", default="", type=str, help="Name of dataset if evaluation module is dataset specific."
|
| 63 |
+
)
|
| 64 |
+
parser_create.add_argument("--module_description", type=str, help="Short description of evaluation module.")
|
| 65 |
+
parser_create.add_argument("--output_dir", default=Path.cwd(), type=str, help="Path to output directory.")
|
| 66 |
+
parser_create.add_argument(
|
| 67 |
+
"--organization", default=None, type=str, help="Organization on the Hub to push evaluation module to."
|
| 68 |
+
)
|
| 69 |
+
parser_create.add_argument("--private", action="store_true", help="Sets evaluation module repository to private.")
|
| 70 |
+
args = vars(parser.parse_args())
|
| 71 |
+
|
| 72 |
+
if args["module_type"] not in ["metric", "comparison", "measurement"]:
|
| 73 |
+
raise ValueError("The module_type needs to be one of metric, comparison, or measurement")
|
| 74 |
+
|
| 75 |
+
if "-" in args["module_name"]:
|
| 76 |
+
raise ValueError("Hyphens ('-') are not allowed in module names.")
|
| 77 |
+
|
| 78 |
+
output_dir = Path(args["output_dir"])
|
| 79 |
+
organization = args["organization"]
|
| 80 |
+
module_slug = args["module_name"].lower().replace(" ", "_")
|
| 81 |
+
|
| 82 |
+
if organization is None:
|
| 83 |
+
hfapi = HfApi()
|
| 84 |
+
namespace = hfapi.whoami()["name"]
|
| 85 |
+
else:
|
| 86 |
+
namespace = organization
|
| 87 |
+
args["namespace"] = namespace
|
| 88 |
+
repo_url = f"https://huggingface.co/spaces/{namespace}/{module_slug}"
|
| 89 |
+
|
| 90 |
+
try:
|
| 91 |
+
create_repo(namespace + "/" + module_slug, repo_type="space", space_sdk="gradio", private=args["private"])
|
| 92 |
+
except Exception as exception:
|
| 93 |
+
logger.error(
|
| 94 |
+
f"Could not create Space for module at hf.co/spaces/{namespace}/{module_slug}. Make sure this space does not exist already."
|
| 95 |
+
)
|
| 96 |
+
raise exception
|
| 97 |
+
subprocess.run(
|
| 98 |
+
f"git clone {repo_url}".split(),
|
| 99 |
+
stderr=subprocess.PIPE,
|
| 100 |
+
stdout=subprocess.PIPE,
|
| 101 |
+
check=True,
|
| 102 |
+
encoding="utf-8",
|
| 103 |
+
cwd=output_dir,
|
| 104 |
+
env=os.environ.copy(),
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
repo = Repository(
|
| 108 |
+
local_dir=output_dir / module_slug,
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
cookiecutter(
|
| 112 |
+
"https://github.com/huggingface/evaluate/",
|
| 113 |
+
directory="templates",
|
| 114 |
+
no_input=True,
|
| 115 |
+
extra_context=args,
|
| 116 |
+
output_dir=output_dir,
|
| 117 |
+
overwrite_if_exists=True,
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
repo.git_add()
|
| 121 |
+
repo.git_commit("add module default template")
|
| 122 |
+
repo.git_push()
|
| 123 |
+
|
| 124 |
+
print(
|
| 125 |
+
INSTRUCTIONS.format(
|
| 126 |
+
module_name=args["module_name"],
|
| 127 |
+
module_type=args["module_type"],
|
| 128 |
+
module_slug=module_slug,
|
| 129 |
+
namespace=namespace,
|
| 130 |
+
repo_url=repo_url,
|
| 131 |
+
output_dir=output_dir,
|
| 132 |
+
)
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
if __name__ == "__main__":
|
| 137 |
+
main()
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluation_suite/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (7.41 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__init__.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Datasets Authors and the TensorFlow Datasets Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
from transformers.pipelines import SUPPORTED_TASKS as SUPPORTED_PIPELINE_TASKS
|
| 18 |
+
from transformers.pipelines import TASK_ALIASES
|
| 19 |
+
from transformers.pipelines import check_task as check_pipeline_task
|
| 20 |
+
|
| 21 |
+
TRANSFORMERS_AVAILABLE = True
|
| 22 |
+
except ImportError:
|
| 23 |
+
TRANSFORMERS_AVAILABLE = False
|
| 24 |
+
|
| 25 |
+
from typing import Dict, List
|
| 26 |
+
|
| 27 |
+
from .audio_classification import AudioClassificationEvaluator
|
| 28 |
+
from .automatic_speech_recognition import AutomaticSpeechRecognitionEvaluator
|
| 29 |
+
from .base import Evaluator
|
| 30 |
+
from .image_classification import ImageClassificationEvaluator
|
| 31 |
+
from .question_answering import QuestionAnsweringEvaluator
|
| 32 |
+
from .text2text_generation import SummarizationEvaluator, Text2TextGenerationEvaluator, TranslationEvaluator
|
| 33 |
+
from .text_classification import TextClassificationEvaluator
|
| 34 |
+
from .text_generation import TextGenerationEvaluator
|
| 35 |
+
from .token_classification import TokenClassificationEvaluator
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
SUPPORTED_EVALUATOR_TASKS = {
|
| 39 |
+
"text-classification": {
|
| 40 |
+
"implementation": TextClassificationEvaluator,
|
| 41 |
+
"default_metric_name": "accuracy",
|
| 42 |
+
},
|
| 43 |
+
"image-classification": {
|
| 44 |
+
"implementation": ImageClassificationEvaluator,
|
| 45 |
+
"default_metric_name": "accuracy",
|
| 46 |
+
},
|
| 47 |
+
"question-answering": {
|
| 48 |
+
"implementation": QuestionAnsweringEvaluator,
|
| 49 |
+
"default_metric_name": "squad",
|
| 50 |
+
},
|
| 51 |
+
"token-classification": {
|
| 52 |
+
"implementation": TokenClassificationEvaluator,
|
| 53 |
+
"default_metric_name": "seqeval",
|
| 54 |
+
},
|
| 55 |
+
"text-generation": {
|
| 56 |
+
"implementation": TextGenerationEvaluator,
|
| 57 |
+
"default_metric_name": "word_count",
|
| 58 |
+
},
|
| 59 |
+
"text2text-generation": {
|
| 60 |
+
"implementation": Text2TextGenerationEvaluator,
|
| 61 |
+
"default_metric_name": "bleu",
|
| 62 |
+
},
|
| 63 |
+
"summarization": {
|
| 64 |
+
"implementation": SummarizationEvaluator,
|
| 65 |
+
"default_metric_name": "rouge",
|
| 66 |
+
},
|
| 67 |
+
"translation": {
|
| 68 |
+
"implementation": TranslationEvaluator,
|
| 69 |
+
"default_metric_name": "bleu",
|
| 70 |
+
},
|
| 71 |
+
"automatic-speech-recognition": {
|
| 72 |
+
"implementation": AutomaticSpeechRecognitionEvaluator,
|
| 73 |
+
"default_metric_name": "wer",
|
| 74 |
+
},
|
| 75 |
+
"audio-classification": {
|
| 76 |
+
"implementation": AudioClassificationEvaluator,
|
| 77 |
+
"default_metric_name": "accuracy",
|
| 78 |
+
},
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def get_supported_tasks() -> List[str]:
|
| 83 |
+
"""
|
| 84 |
+
Returns a list of supported task strings.
|
| 85 |
+
"""
|
| 86 |
+
return list(SUPPORTED_EVALUATOR_TASKS.keys())
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def check_task(task: str) -> Dict:
|
| 90 |
+
"""
|
| 91 |
+
Checks an incoming task string, to validate it's correct and returns the default Evaluator class and default metric
|
| 92 |
+
name. It first performs a check to validata that the string is a valid `Pipeline` task, then it checks if it's a
|
| 93 |
+
valid `Evaluator` task. `Evaluator` tasks are a substet of `Pipeline` tasks.
|
| 94 |
+
Args:
|
| 95 |
+
task (`str`):
|
| 96 |
+
The task defining which evaluator will be returned. Currently accepted tasks are:
|
| 97 |
+
- `"image-classification"`
|
| 98 |
+
- `"question-answering"`
|
| 99 |
+
- `"text-classification"` (alias `"sentiment-analysis"` available)
|
| 100 |
+
- `"token-classification"`
|
| 101 |
+
Returns:
|
| 102 |
+
task_defaults: `dict`, contains the implementasion class of a give Evaluator and the default metric name.
|
| 103 |
+
"""
|
| 104 |
+
if task in TASK_ALIASES:
|
| 105 |
+
task = TASK_ALIASES[task]
|
| 106 |
+
if not check_pipeline_task(task):
|
| 107 |
+
raise KeyError(f"Unknown task {task}, available tasks are: {get_supported_tasks()}.")
|
| 108 |
+
if task in SUPPORTED_EVALUATOR_TASKS.keys() and task in SUPPORTED_PIPELINE_TASKS.keys():
|
| 109 |
+
return SUPPORTED_EVALUATOR_TASKS[task]
|
| 110 |
+
raise KeyError(f"Unknown task {task}, available tasks are: {get_supported_tasks()}.")
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def evaluator(task: str = None) -> Evaluator:
|
| 114 |
+
"""
|
| 115 |
+
Utility factory method to build an [`Evaluator`].
|
| 116 |
+
Evaluators encapsulate a task and a default metric name. They leverage `pipeline` functionality from `transformers`
|
| 117 |
+
to simplify the evaluation of multiple combinations of models, datasets and metrics for a given task.
|
| 118 |
+
Args:
|
| 119 |
+
task (`str`):
|
| 120 |
+
The task defining which evaluator will be returned. Currently accepted tasks are:
|
| 121 |
+
- `"image-classification"`: will return a [`ImageClassificationEvaluator`].
|
| 122 |
+
- `"question-answering"`: will return a [`QuestionAnsweringEvaluator`].
|
| 123 |
+
- `"text-classification"` (alias `"sentiment-analysis"` available): will return a [`TextClassificationEvaluator`].
|
| 124 |
+
- `"token-classification"`: will return a [`TokenClassificationEvaluator`].
|
| 125 |
+
Returns:
|
| 126 |
+
[`Evaluator`]: An evaluator suitable for the task.
|
| 127 |
+
Examples:
|
| 128 |
+
```python
|
| 129 |
+
>>> from evaluate import evaluator
|
| 130 |
+
>>> # Sentiment analysis evaluator
|
| 131 |
+
>>> evaluator("sentiment-analysis")
|
| 132 |
+
```"""
|
| 133 |
+
if not TRANSFORMERS_AVAILABLE:
|
| 134 |
+
raise ImportError(
|
| 135 |
+
"If you want to use the `Evaluator` you need `transformers`. Run `pip install evaluate[transformers]`."
|
| 136 |
+
)
|
| 137 |
+
targeted_task = check_task(task)
|
| 138 |
+
evaluator_class = targeted_task["implementation"]
|
| 139 |
+
default_metric_name = targeted_task["default_metric_name"]
|
| 140 |
+
return evaluator_class(task=task, default_metric_name=default_metric_name)
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (5.01 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/audio_classification.cpython-312.pyc
ADDED
|
Binary file (6.12 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/automatic_speech_recognition.cpython-312.pyc
ADDED
|
Binary file (4.64 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/base.cpython-312.pyc
ADDED
|
Binary file (23.6 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/image_classification.cpython-312.pyc
ADDED
|
Binary file (5.07 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/question_answering.cpython-312.pyc
ADDED
|
Binary file (10 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text2text_generation.cpython-312.pyc
ADDED
|
Binary file (9.07 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text_classification.cpython-312.pyc
ADDED
|
Binary file (6.9 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/text_generation.cpython-312.pyc
ADDED
|
Binary file (3.02 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/token_classification.cpython-312.pyc
ADDED
|
Binary file (11.9 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (4.41 kB). View file
|
|
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/audio_classification.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Evaluate Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from numbers import Number
|
| 16 |
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Union
|
| 17 |
+
|
| 18 |
+
from datasets import Dataset
|
| 19 |
+
from typing_extensions import Literal
|
| 20 |
+
|
| 21 |
+
from ..module import EvaluationModule
|
| 22 |
+
from ..utils.file_utils import add_end_docstrings, add_start_docstrings
|
| 23 |
+
from .base import EVALUATOR_COMPUTE_RETURN_DOCSTRING, EVALUTOR_COMPUTE_START_DOCSTRING, Evaluator
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
if TYPE_CHECKING:
|
| 27 |
+
from transformers import FeatureExtractionMixin, Pipeline, PreTrainedModel, PreTrainedTokenizer, TFPreTrainedModel
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
TASK_DOCUMENTATION = r"""
|
| 31 |
+
Examples:
|
| 32 |
+
|
| 33 |
+
<Tip>
|
| 34 |
+
|
| 35 |
+
Remember that, in order to process audio files, you need ffmpeg installed (https://ffmpeg.org/download.html)
|
| 36 |
+
|
| 37 |
+
</Tip>
|
| 38 |
+
|
| 39 |
+
```python
|
| 40 |
+
>>> from evaluate import evaluator
|
| 41 |
+
>>> from datasets import load_dataset
|
| 42 |
+
|
| 43 |
+
>>> task_evaluator = evaluator("audio-classification")
|
| 44 |
+
>>> data = load_dataset("superb", 'ks', split="test[:40]")
|
| 45 |
+
>>> results = task_evaluator.compute(
|
| 46 |
+
>>> model_or_pipeline=""superb/wav2vec2-base-superb-ks"",
|
| 47 |
+
>>> data=data,
|
| 48 |
+
>>> label_column="label",
|
| 49 |
+
>>> input_column="file",
|
| 50 |
+
>>> metric="accuracy",
|
| 51 |
+
>>> label_mapping={0: "yes", 1: "no", 2: "up", 3: "down"}
|
| 52 |
+
>>> )
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
<Tip>
|
| 56 |
+
|
| 57 |
+
The evaluator supports raw audio data as well, in the form of a numpy array. However, be aware that calling
|
| 58 |
+
the audio column automatically decodes and resamples the audio files, which can be slow for large datasets.
|
| 59 |
+
|
| 60 |
+
</Tip>
|
| 61 |
+
|
| 62 |
+
```python
|
| 63 |
+
>>> from evaluate import evaluator
|
| 64 |
+
>>> from datasets import load_dataset
|
| 65 |
+
|
| 66 |
+
>>> task_evaluator = evaluator("audio-classification")
|
| 67 |
+
>>> data = load_dataset("superb", 'ks', split="test[:40]")
|
| 68 |
+
>>> data = data.map(lambda example: {"audio": example["audio"]["array"]})
|
| 69 |
+
>>> results = task_evaluator.compute(
|
| 70 |
+
>>> model_or_pipeline=""superb/wav2vec2-base-superb-ks"",
|
| 71 |
+
>>> data=data,
|
| 72 |
+
>>> label_column="label",
|
| 73 |
+
>>> input_column="audio",
|
| 74 |
+
>>> metric="accuracy",
|
| 75 |
+
>>> label_mapping={0: "yes", 1: "no", 2: "up", 3: "down"}
|
| 76 |
+
>>> )
|
| 77 |
+
```
|
| 78 |
+
"""
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
class AudioClassificationEvaluator(Evaluator):
|
| 82 |
+
"""
|
| 83 |
+
Audio classification evaluator.
|
| 84 |
+
This audio classification evaluator can currently be loaded from [`evaluator`] using the default task name
|
| 85 |
+
`audio-classification`.
|
| 86 |
+
Methods in this class assume a data format compatible with the [`transformers.AudioClassificationPipeline`].
|
| 87 |
+
"""
|
| 88 |
+
|
| 89 |
+
PIPELINE_KWARGS = {}
|
| 90 |
+
|
| 91 |
+
def __init__(self, task="audio-classification", default_metric_name=None):
|
| 92 |
+
super().__init__(task, default_metric_name=default_metric_name)
|
| 93 |
+
|
| 94 |
+
def predictions_processor(self, predictions, label_mapping):
|
| 95 |
+
pred_label = [max(pred, key=lambda x: x["score"])["label"] for pred in predictions]
|
| 96 |
+
pred_label = [label_mapping[pred] if label_mapping is not None else pred for pred in pred_label]
|
| 97 |
+
|
| 98 |
+
return {"predictions": pred_label}
|
| 99 |
+
|
| 100 |
+
@add_start_docstrings(EVALUTOR_COMPUTE_START_DOCSTRING)
|
| 101 |
+
@add_end_docstrings(EVALUATOR_COMPUTE_RETURN_DOCSTRING, TASK_DOCUMENTATION)
|
| 102 |
+
def compute(
|
| 103 |
+
self,
|
| 104 |
+
model_or_pipeline: Union[
|
| 105 |
+
str, "Pipeline", Callable, "PreTrainedModel", "TFPreTrainedModel" # noqa: F821
|
| 106 |
+
] = None,
|
| 107 |
+
data: Union[str, Dataset] = None,
|
| 108 |
+
subset: Optional[str] = None,
|
| 109 |
+
split: Optional[str] = None,
|
| 110 |
+
metric: Union[str, EvaluationModule] = None,
|
| 111 |
+
tokenizer: Optional[Union[str, "PreTrainedTokenizer"]] = None, # noqa: F821
|
| 112 |
+
feature_extractor: Optional[Union[str, "FeatureExtractionMixin"]] = None, # noqa: F821
|
| 113 |
+
strategy: Literal["simple", "bootstrap"] = "simple",
|
| 114 |
+
confidence_level: float = 0.95,
|
| 115 |
+
n_resamples: int = 9999,
|
| 116 |
+
device: int = None,
|
| 117 |
+
random_state: Optional[int] = None,
|
| 118 |
+
input_column: str = "file",
|
| 119 |
+
label_column: str = "label",
|
| 120 |
+
label_mapping: Optional[Dict[str, Number]] = None,
|
| 121 |
+
) -> Tuple[Dict[str, float], Any]:
|
| 122 |
+
|
| 123 |
+
"""
|
| 124 |
+
input_column (`str`, defaults to `"file"`):
|
| 125 |
+
The name of the column containing either the audio files or a raw waveform, represented as a numpy array, in the dataset specified by `data`.
|
| 126 |
+
label_column (`str`, defaults to `"label"`):
|
| 127 |
+
The name of the column containing the labels in the dataset specified by `data`.
|
| 128 |
+
label_mapping (`Dict[str, Number]`, *optional*, defaults to `None`):
|
| 129 |
+
We want to map class labels defined by the model in the pipeline to values consistent with those
|
| 130 |
+
defined in the `label_column` of the `data` dataset.
|
| 131 |
+
"""
|
| 132 |
+
|
| 133 |
+
result = super().compute(
|
| 134 |
+
model_or_pipeline=model_or_pipeline,
|
| 135 |
+
data=data,
|
| 136 |
+
subset=subset,
|
| 137 |
+
split=split,
|
| 138 |
+
metric=metric,
|
| 139 |
+
tokenizer=tokenizer,
|
| 140 |
+
feature_extractor=feature_extractor,
|
| 141 |
+
strategy=strategy,
|
| 142 |
+
confidence_level=confidence_level,
|
| 143 |
+
n_resamples=n_resamples,
|
| 144 |
+
device=device,
|
| 145 |
+
random_state=random_state,
|
| 146 |
+
input_column=input_column,
|
| 147 |
+
label_column=label_column,
|
| 148 |
+
label_mapping=label_mapping,
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
return result
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/automatic_speech_recognition.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Evaluate Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Union
|
| 16 |
+
|
| 17 |
+
from datasets import Dataset
|
| 18 |
+
from typing_extensions import Literal
|
| 19 |
+
|
| 20 |
+
from ..module import EvaluationModule
|
| 21 |
+
from ..utils.file_utils import add_end_docstrings, add_start_docstrings
|
| 22 |
+
from .base import EVALUATOR_COMPUTE_RETURN_DOCSTRING, EVALUTOR_COMPUTE_START_DOCSTRING, Evaluator
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
if TYPE_CHECKING:
|
| 26 |
+
from transformers import Pipeline, PreTrainedModel, PreTrainedTokenizer, TFPreTrainedModel
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
TASK_DOCUMENTATION = r"""
|
| 30 |
+
Examples:
|
| 31 |
+
```python
|
| 32 |
+
>>> from evaluate import evaluator
|
| 33 |
+
>>> from datasets import load_dataset
|
| 34 |
+
>>> task_evaluator = evaluator("automatic-speech-recognition")
|
| 35 |
+
>>> data = load_dataset("mozilla-foundation/common_voice_11_0", "en", split="validation[:40]")
|
| 36 |
+
>>> results = task_evaluator.compute(
|
| 37 |
+
>>> model_or_pipeline="https://huggingface.co/openai/whisper-tiny.en",
|
| 38 |
+
>>> data=data,
|
| 39 |
+
>>> input_column="path",
|
| 40 |
+
>>> label_column="sentence",
|
| 41 |
+
>>> metric="wer",
|
| 42 |
+
>>> )
|
| 43 |
+
```
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
class AutomaticSpeechRecognitionEvaluator(Evaluator):
|
| 48 |
+
"""
|
| 49 |
+
Automatic speech recognition evaluator.
|
| 50 |
+
This automatic speech recognition evaluator can currently be loaded from [`evaluator`] using the default task name
|
| 51 |
+
`automatic-speech-recognition`.
|
| 52 |
+
Methods in this class assume a data format compatible with the [`AutomaticSpeechRecognitionPipeline`].
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
PIPELINE_KWARGS = {"truncation": True}
|
| 56 |
+
|
| 57 |
+
def __init__(self, task="automatic-speech-recognition", default_metric_name=None):
|
| 58 |
+
super().__init__(task, default_metric_name=default_metric_name)
|
| 59 |
+
|
| 60 |
+
def predictions_processor(self, predictions, label_mapping):
|
| 61 |
+
return {"predictions": [pred["text"] for pred in predictions]}
|
| 62 |
+
|
| 63 |
+
@add_start_docstrings(EVALUTOR_COMPUTE_START_DOCSTRING)
|
| 64 |
+
@add_end_docstrings(EVALUATOR_COMPUTE_RETURN_DOCSTRING, TASK_DOCUMENTATION)
|
| 65 |
+
def compute(
|
| 66 |
+
self,
|
| 67 |
+
model_or_pipeline: Union[
|
| 68 |
+
str, "Pipeline", Callable, "PreTrainedModel", "TFPreTrainedModel" # noqa: F821
|
| 69 |
+
] = None,
|
| 70 |
+
data: Union[str, Dataset] = None,
|
| 71 |
+
subset: Optional[str] = None,
|
| 72 |
+
split: Optional[str] = None,
|
| 73 |
+
metric: Union[str, EvaluationModule] = None,
|
| 74 |
+
tokenizer: Optional[Union[str, "PreTrainedTokenizer"]] = None, # noqa: F821
|
| 75 |
+
strategy: Literal["simple", "bootstrap"] = "simple",
|
| 76 |
+
confidence_level: float = 0.95,
|
| 77 |
+
n_resamples: int = 9999,
|
| 78 |
+
device: int = None,
|
| 79 |
+
random_state: Optional[int] = None,
|
| 80 |
+
input_column: str = "path",
|
| 81 |
+
label_column: str = "sentence",
|
| 82 |
+
generation_kwargs: dict = None,
|
| 83 |
+
) -> Tuple[Dict[str, float], Any]:
|
| 84 |
+
"""
|
| 85 |
+
input_column (`str`, defaults to `"path"`):
|
| 86 |
+
the name of the column containing the input audio path in the dataset specified by `data`.
|
| 87 |
+
label_column (`str`, defaults to `"sentence"`):
|
| 88 |
+
the name of the column containing the labels in the dataset specified by `data`.
|
| 89 |
+
generation_kwargs (`Dict`, *optional*, defaults to `None`):
|
| 90 |
+
The generation kwargs are passed to the pipeline and set the text generation strategy.
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
if generation_kwargs is not None:
|
| 94 |
+
self.PIPELINE_KWARGS.update(generation_kwargs)
|
| 95 |
+
|
| 96 |
+
result = super().compute(
|
| 97 |
+
model_or_pipeline=model_or_pipeline,
|
| 98 |
+
data=data,
|
| 99 |
+
subset=subset,
|
| 100 |
+
split=split,
|
| 101 |
+
metric=metric,
|
| 102 |
+
tokenizer=tokenizer,
|
| 103 |
+
strategy=strategy,
|
| 104 |
+
confidence_level=confidence_level,
|
| 105 |
+
n_resamples=n_resamples,
|
| 106 |
+
device=device,
|
| 107 |
+
random_state=random_state,
|
| 108 |
+
input_column=input_column,
|
| 109 |
+
label_column=label_column,
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
return result
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/base.py
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Datasets Authors and the TensorFlow Datasets Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from abc import ABC, abstractmethod
|
| 16 |
+
from numbers import Number
|
| 17 |
+
from typing import Any, Callable, Dict, List, Optional, Union
|
| 18 |
+
|
| 19 |
+
# Lint as: python3
|
| 20 |
+
from datasets import Dataset, load_dataset
|
| 21 |
+
|
| 22 |
+
from evaluate.evaluator.utils import choose_split
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
try:
|
| 26 |
+
from scipy.stats import bootstrap
|
| 27 |
+
|
| 28 |
+
SCIPY_AVAILABLE = True
|
| 29 |
+
except ImportError:
|
| 30 |
+
SCIPY_AVAILABLE = False
|
| 31 |
+
|
| 32 |
+
try:
|
| 33 |
+
import transformers
|
| 34 |
+
from transformers import Pipeline, pipeline
|
| 35 |
+
|
| 36 |
+
TRANSFORMERS_AVAILABLE = True
|
| 37 |
+
except ImportError:
|
| 38 |
+
TRANSFORMERS_AVAILABLE = False
|
| 39 |
+
|
| 40 |
+
from time import perf_counter
|
| 41 |
+
|
| 42 |
+
from typing_extensions import Literal
|
| 43 |
+
|
| 44 |
+
from ..loading import load
|
| 45 |
+
from ..module import EvaluationModule
|
| 46 |
+
from ..utils.logging import get_logger
|
| 47 |
+
from .utils import DatasetColumn
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
logger = get_logger(__name__)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
EVALUTOR_COMPUTE_START_DOCSTRING = r"""
|
| 54 |
+
Compute the metric for a given pipeline and dataset combination.
|
| 55 |
+
Args:
|
| 56 |
+
model_or_pipeline (`str` or `Pipeline` or `Callable` or `PreTrainedModel` or `TFPreTrainedModel`, defaults to `None`):
|
| 57 |
+
If the argument in not specified, we initialize the default pipeline for the task (in this case
|
| 58 |
+
`text-classification` or its alias - `sentiment-analysis`). If the argument is of the type `str` or
|
| 59 |
+
is a model instance, we use it to initialize a new `Pipeline` with the given model. Otherwise we assume the
|
| 60 |
+
argument specifies a pre-initialized pipeline.
|
| 61 |
+
data (`str` or `Dataset`, defaults to `None`):
|
| 62 |
+
Specifies the dataset we will run evaluation on. If it is of type `str`, we treat it as the dataset
|
| 63 |
+
name, and load it. Otherwise we assume it represents a pre-loaded dataset.
|
| 64 |
+
subset (`str`, defaults to `None`):
|
| 65 |
+
Defines which dataset subset to load. If `None` is passed the default subset is loaded.
|
| 66 |
+
split (`str`, defaults to `None`):
|
| 67 |
+
Defines which dataset split to load. If `None` is passed, infers based on the `choose_split` function.
|
| 68 |
+
metric (`str` or `EvaluationModule`, defaults to `None`):
|
| 69 |
+
Specifies the metric we use in evaluator. If it is of type `str`, we treat it as the metric name, and
|
| 70 |
+
load it. Otherwise we assume it represents a pre-loaded metric.
|
| 71 |
+
tokenizer (`str` or `PreTrainedTokenizer`, *optional*, defaults to `None`):
|
| 72 |
+
Argument can be used to overwrite a default tokenizer if `model_or_pipeline` represents a model for
|
| 73 |
+
which we build a pipeline. If `model_or_pipeline` is `None` or a pre-initialized pipeline, we ignore
|
| 74 |
+
this argument.
|
| 75 |
+
strategy (`Literal["simple", "bootstrap"]`, defaults to "simple"):
|
| 76 |
+
specifies the evaluation strategy. Possible values are:
|
| 77 |
+
- `"simple"` - we evaluate the metric and return the scores.
|
| 78 |
+
- `"bootstrap"` - on top of computing the metric scores, we calculate the confidence interval for each
|
| 79 |
+
of the returned metric keys, using `scipy`'s `bootstrap` method
|
| 80 |
+
https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.bootstrap.html.
|
| 81 |
+
confidence_level (`float`, defaults to `0.95`):
|
| 82 |
+
The `confidence_level` value passed to `bootstrap` if `"bootstrap"` strategy is chosen.
|
| 83 |
+
n_resamples (`int`, defaults to `9999`):
|
| 84 |
+
The `n_resamples` value passed to `bootstrap` if `"bootstrap"` strategy is chosen.
|
| 85 |
+
device (`int`, defaults to `None`):
|
| 86 |
+
Device ordinal for CPU/GPU support of the pipeline. Setting this to -1 will leverage CPU, a positive
|
| 87 |
+
integer will run the model on the associated CUDA device ID. If `None` is provided it will be inferred and
|
| 88 |
+
CUDA:0 used if available, CPU otherwise.
|
| 89 |
+
random_state (`int`, *optional*, defaults to `None`):
|
| 90 |
+
The `random_state` value passed to `bootstrap` if `"bootstrap"` strategy is chosen. Useful for
|
| 91 |
+
debugging.
|
| 92 |
+
"""
|
| 93 |
+
|
| 94 |
+
EVALUATOR_COMPUTE_RETURN_DOCSTRING = r"""
|
| 95 |
+
Return:
|
| 96 |
+
A `Dict`. The keys represent metric keys calculated for the `metric` spefied in function arguments. For the
|
| 97 |
+
`"simple"` strategy, the value is the metric score. For the `"bootstrap"` strategy, the value is a `Dict`
|
| 98 |
+
containing the score, the confidence interval and the standard error calculated for each metric key.
|
| 99 |
+
"""
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class Evaluator(ABC):
|
| 103 |
+
"""
|
| 104 |
+
The [`Evaluator`] class is the class from which all evaluators inherit. Refer to this class for methods shared across
|
| 105 |
+
different evaluators.
|
| 106 |
+
Base class implementing evaluator operations.
|
| 107 |
+
"""
|
| 108 |
+
|
| 109 |
+
PIPELINE_KWARGS = {}
|
| 110 |
+
METRIC_KWARGS = {}
|
| 111 |
+
|
| 112 |
+
def __init__(self, task: str, default_metric_name: str = None):
|
| 113 |
+
if not TRANSFORMERS_AVAILABLE:
|
| 114 |
+
raise ImportError(
|
| 115 |
+
"If you want to use the `Evaluator` you need `transformers`. Run `pip install evaluate[evaluator]`."
|
| 116 |
+
)
|
| 117 |
+
if not SCIPY_AVAILABLE:
|
| 118 |
+
raise ImportError(
|
| 119 |
+
"If you want to use the `Evaluator` you need `scipy>=1.7.1`. Run `pip install evaluate[evaluator]`."
|
| 120 |
+
)
|
| 121 |
+
self.task = task
|
| 122 |
+
self.default_metric_name = default_metric_name
|
| 123 |
+
|
| 124 |
+
@staticmethod
|
| 125 |
+
def _compute_confidence_interval(
|
| 126 |
+
metric,
|
| 127 |
+
metric_inputs,
|
| 128 |
+
metric_keys: List[str],
|
| 129 |
+
confidence_level: float = 0.95,
|
| 130 |
+
n_resamples: int = 9999,
|
| 131 |
+
random_state: Optional[int] = None,
|
| 132 |
+
) -> Dict[str, Any]:
|
| 133 |
+
"""
|
| 134 |
+
A utility function enabling the confidence interval calculation for metrics computed
|
| 135 |
+
by the evaluator based on `scipy`'s `bootstrap` method.
|
| 136 |
+
"""
|
| 137 |
+
|
| 138 |
+
# bootstrap only works with functions that use args and no kwargs
|
| 139 |
+
def build_args_metric(metric, key, **kwargs):
|
| 140 |
+
def args_metric(*args):
|
| 141 |
+
return metric.compute(**{k: v for k, v in zip(kwargs.keys(), args)})[key]
|
| 142 |
+
|
| 143 |
+
return args_metric
|
| 144 |
+
|
| 145 |
+
bootstrap_dict = {}
|
| 146 |
+
for key in metric_keys:
|
| 147 |
+
bs = bootstrap(
|
| 148 |
+
data=list(metric_inputs.values()),
|
| 149 |
+
statistic=build_args_metric(metric, key, **metric_inputs),
|
| 150 |
+
paired=True,
|
| 151 |
+
vectorized=False,
|
| 152 |
+
confidence_level=confidence_level,
|
| 153 |
+
n_resamples=n_resamples,
|
| 154 |
+
random_state=random_state,
|
| 155 |
+
)
|
| 156 |
+
bootstrap_dict[key] = {
|
| 157 |
+
"confidence_interval": (bs.confidence_interval.low, bs.confidence_interval.high),
|
| 158 |
+
"standard_error": bs.standard_error,
|
| 159 |
+
}
|
| 160 |
+
return bootstrap_dict
|
| 161 |
+
|
| 162 |
+
@staticmethod
|
| 163 |
+
def _compute_time_perf(start_time: float, end_time: float, num_samples: int) -> Dict[str, Any]:
|
| 164 |
+
"""
|
| 165 |
+
A utility function computing time performance metrics:
|
| 166 |
+
- `total_time_in_seconds` - pipeline inference runtime for the evaluation data in seconds,
|
| 167 |
+
- `samples_per_second` - pipeline throughput in the number of samples per second.
|
| 168 |
+
- `latency_in_seconds` - pipeline inference runtime for the evaluation data in seconds per sample,
|
| 169 |
+
|
| 170 |
+
"""
|
| 171 |
+
latency = end_time - start_time
|
| 172 |
+
throughput = num_samples / latency
|
| 173 |
+
latency_sample = 1.0 / throughput
|
| 174 |
+
|
| 175 |
+
return {
|
| 176 |
+
"total_time_in_seconds": latency,
|
| 177 |
+
"samples_per_second": throughput,
|
| 178 |
+
"latency_in_seconds": latency_sample,
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
@staticmethod
|
| 182 |
+
def _infer_device() -> int:
|
| 183 |
+
"""Helper function to check if GPU or CPU is available for inference."""
|
| 184 |
+
# try infer with torch first
|
| 185 |
+
try:
|
| 186 |
+
import torch
|
| 187 |
+
|
| 188 |
+
if torch.cuda.is_available():
|
| 189 |
+
device = 0 # first GPU
|
| 190 |
+
else:
|
| 191 |
+
device = -1 # CPU
|
| 192 |
+
except ImportError:
|
| 193 |
+
# if not available try TF
|
| 194 |
+
try:
|
| 195 |
+
import tensorflow as tf
|
| 196 |
+
|
| 197 |
+
if len(tf.config.list_physical_devices("GPU")) > 0:
|
| 198 |
+
device = 0 # first GPU
|
| 199 |
+
else:
|
| 200 |
+
device = -1 # CPU
|
| 201 |
+
except ImportError:
|
| 202 |
+
device = -1
|
| 203 |
+
|
| 204 |
+
if device == -1:
|
| 205 |
+
logger.info("No GPU found. The default device for pipeline inference is set to CPU.")
|
| 206 |
+
else:
|
| 207 |
+
logger.info("GPU found. The default device for pipeline inference is set to GPU (CUDA:0).")
|
| 208 |
+
|
| 209 |
+
return device
|
| 210 |
+
|
| 211 |
+
@abstractmethod
|
| 212 |
+
def predictions_processor(self, *args, **kwargs):
|
| 213 |
+
"""
|
| 214 |
+
A core method of the `Evaluator` class, which processes the pipeline outputs for compatibility with the metric.
|
| 215 |
+
"""
|
| 216 |
+
raise NotImplementedError()
|
| 217 |
+
|
| 218 |
+
def compute(
|
| 219 |
+
self,
|
| 220 |
+
model_or_pipeline: Union[
|
| 221 |
+
str, "Pipeline", Callable, "PreTrainedModel", "TFPreTrainedModel" # noqa: F821
|
| 222 |
+
] = None,
|
| 223 |
+
data: Union[str, Dataset] = None,
|
| 224 |
+
subset: Optional[str] = None,
|
| 225 |
+
split: Optional[str] = None,
|
| 226 |
+
metric: Union[str, EvaluationModule] = None,
|
| 227 |
+
tokenizer: Optional[Union[str, "PreTrainedTokenizer"]] = None, # noqa: F821
|
| 228 |
+
feature_extractor: Optional[Union[str, "FeatureExtractionMixin"]] = None, # noqa: F821
|
| 229 |
+
strategy: Literal["simple", "bootstrap"] = "simple",
|
| 230 |
+
confidence_level: float = 0.95,
|
| 231 |
+
n_resamples: int = 9999,
|
| 232 |
+
device: int = None,
|
| 233 |
+
random_state: Optional[int] = None,
|
| 234 |
+
input_column: str = "text",
|
| 235 |
+
label_column: str = "label",
|
| 236 |
+
label_mapping: Optional[Dict[str, Number]] = None,
|
| 237 |
+
) -> Dict[str, float]:
|
| 238 |
+
|
| 239 |
+
result = {}
|
| 240 |
+
|
| 241 |
+
self.check_for_mismatch_in_device_setup(device, model_or_pipeline)
|
| 242 |
+
|
| 243 |
+
# Prepare inputs
|
| 244 |
+
data = self.load_data(data=data, subset=subset, split=split)
|
| 245 |
+
metric_inputs, pipe_inputs = self.prepare_data(data=data, input_column=input_column, label_column=label_column)
|
| 246 |
+
pipe = self.prepare_pipeline(
|
| 247 |
+
model_or_pipeline=model_or_pipeline,
|
| 248 |
+
tokenizer=tokenizer,
|
| 249 |
+
feature_extractor=feature_extractor,
|
| 250 |
+
device=device,
|
| 251 |
+
)
|
| 252 |
+
metric = self.prepare_metric(metric)
|
| 253 |
+
|
| 254 |
+
# Compute predictions
|
| 255 |
+
predictions, perf_results = self.call_pipeline(pipe, pipe_inputs)
|
| 256 |
+
predictions = self.predictions_processor(predictions, label_mapping)
|
| 257 |
+
|
| 258 |
+
metric_inputs.update(predictions)
|
| 259 |
+
|
| 260 |
+
# Compute metrics from references and predictions
|
| 261 |
+
metric_results = self.compute_metric(
|
| 262 |
+
metric=metric,
|
| 263 |
+
metric_inputs=metric_inputs,
|
| 264 |
+
strategy=strategy,
|
| 265 |
+
confidence_level=confidence_level,
|
| 266 |
+
n_resamples=n_resamples,
|
| 267 |
+
random_state=random_state,
|
| 268 |
+
)
|
| 269 |
+
|
| 270 |
+
# TODO: To clarify why `wer` and `cer` return float
|
| 271 |
+
# even though metric.compute contract says that it
|
| 272 |
+
# returns Optional[dict].
|
| 273 |
+
if type(metric_results) is float:
|
| 274 |
+
metric_results = {metric.name: metric_results}
|
| 275 |
+
|
| 276 |
+
result.update(metric_results)
|
| 277 |
+
result.update(perf_results)
|
| 278 |
+
|
| 279 |
+
return result
|
| 280 |
+
|
| 281 |
+
@staticmethod
|
| 282 |
+
def check_for_mismatch_in_device_setup(device, model_or_pipeline):
|
| 283 |
+
if device is not None and device != -1 and isinstance(model_or_pipeline, Pipeline):
|
| 284 |
+
if model_or_pipeline.device.type == "cpu":
|
| 285 |
+
raise ValueError(
|
| 286 |
+
"The value of the `device` kwarg passed to `compute` suggests that this pipe should be run on an "
|
| 287 |
+
"accelerator, but the pipe was instantiated on CPU. Pass `device` to the pipeline during "
|
| 288 |
+
"initialization to use an accelerator, or pass `device=None` to `compute`. "
|
| 289 |
+
)
|
| 290 |
+
elif device != model_or_pipeline.device.index:
|
| 291 |
+
raise ValueError(
|
| 292 |
+
f"This pipeline was instantiated on device {model_or_pipeline.device.index} but device={device} was passed to `compute`."
|
| 293 |
+
)
|
| 294 |
+
|
| 295 |
+
def check_required_columns(self, data: Union[str, Dataset], columns_names: Dict[str, str]):
|
| 296 |
+
"""
|
| 297 |
+
Ensure the columns required for the evaluation are present in the dataset.
|
| 298 |
+
|
| 299 |
+
Args:
|
| 300 |
+
data (`str` or [`Dataset`]):
|
| 301 |
+
Specifies the dataset we will run evaluation on.
|
| 302 |
+
columns_names (`List[str]`):
|
| 303 |
+
List of column names to check in the dataset. The keys are the arguments to the [`evaluate.EvaluationModule.compute`] method,
|
| 304 |
+
while the values are the column names to check.
|
| 305 |
+
|
| 306 |
+
Example:
|
| 307 |
+
|
| 308 |
+
```py
|
| 309 |
+
>>> from datasets import load_dataset
|
| 310 |
+
>>> from evaluate import evaluator
|
| 311 |
+
>>> data = load_dataset("rotten_tomatoes', split="train")
|
| 312 |
+
>>> evaluator.check_required_columns(data, {"input_column": "text", "label_column": "label"})
|
| 313 |
+
```
|
| 314 |
+
"""
|
| 315 |
+
for input_name, column_name in columns_names.items():
|
| 316 |
+
if column_name not in data.column_names:
|
| 317 |
+
raise ValueError(
|
| 318 |
+
f"Invalid `{input_name}` {column_name} specified. The dataset contains the following columns: {data.column_names}."
|
| 319 |
+
)
|
| 320 |
+
|
| 321 |
+
@staticmethod
|
| 322 |
+
def get_dataset_split(data, subset=None, split=None):
|
| 323 |
+
"""
|
| 324 |
+
Infers which split to use if `None` is given.
|
| 325 |
+
|
| 326 |
+
Args:
|
| 327 |
+
data (`str`):
|
| 328 |
+
Name of dataset.
|
| 329 |
+
subset (`str`):
|
| 330 |
+
Name of config for datasets with multiple configurations (e.g. 'glue/cola').
|
| 331 |
+
split (`str`, defaults to `None`):
|
| 332 |
+
Split to use.
|
| 333 |
+
Returns:
|
| 334 |
+
`split`: `str` containing which split to use
|
| 335 |
+
|
| 336 |
+
Example:
|
| 337 |
+
|
| 338 |
+
```py
|
| 339 |
+
>>> from evaluate import evaluator
|
| 340 |
+
>>> evaluator("text-classification").get_dataset_split(data="rotten_tomatoes")
|
| 341 |
+
WARNING:evaluate.evaluator.base:Dataset split not defined! Automatically evaluating with split: TEST
|
| 342 |
+
'test'
|
| 343 |
+
```
|
| 344 |
+
"""
|
| 345 |
+
if split is None:
|
| 346 |
+
split = choose_split(data, subset)
|
| 347 |
+
logger.warning(f"Dataset split not defined! Automatically evaluating with split: {split.upper()}")
|
| 348 |
+
return split
|
| 349 |
+
|
| 350 |
+
def load_data(self, data: Union[str, Dataset], subset: str = None, split: str = None):
|
| 351 |
+
"""
|
| 352 |
+
Load dataset with given subset and split.
|
| 353 |
+
Args:
|
| 354 |
+
data ([`Dataset`] or `str`, defaults to `None`):
|
| 355 |
+
Specifies the dataset we will run evaluation on. If it is of
|
| 356 |
+
type `str`, we treat it as the dataset name, and load it. Otherwise we assume it represents a pre-loaded dataset.
|
| 357 |
+
subset (`str`, defaults to `None`):
|
| 358 |
+
Specifies dataset subset to be passed to `name` in `load_dataset`. To be
|
| 359 |
+
used with datasets with several configurations (e.g. glue/sst2).
|
| 360 |
+
split (`str`, defaults to `None`):
|
| 361 |
+
User-defined dataset split by name (e.g. train, validation, test). Supports slice-split (`test[:n]`).
|
| 362 |
+
If not defined and data is a `str` type, will automatically select the best one via `choose_split()`.
|
| 363 |
+
Returns:
|
| 364 |
+
data ([`Dataset`]): Loaded dataset which will be used for evaluation.
|
| 365 |
+
|
| 366 |
+
Example:
|
| 367 |
+
|
| 368 |
+
```py
|
| 369 |
+
>>> from evaluate import evaluator
|
| 370 |
+
>>> evaluator("text-classification").load_data(data="rotten_tomatoes", split="train")
|
| 371 |
+
Dataset({
|
| 372 |
+
features: ['text', 'label'],
|
| 373 |
+
num_rows: 8530
|
| 374 |
+
})
|
| 375 |
+
```
|
| 376 |
+
"""
|
| 377 |
+
if isinstance(data, str):
|
| 378 |
+
split = self.get_dataset_split(data, subset, split)
|
| 379 |
+
data = load_dataset(data, name=subset, split=split)
|
| 380 |
+
return data
|
| 381 |
+
elif isinstance(data, Dataset):
|
| 382 |
+
if split is not None or subset is not None:
|
| 383 |
+
logger.warning("`data` is a preloaded Dataset! Ignoring `subset` and `split`.")
|
| 384 |
+
return data
|
| 385 |
+
else:
|
| 386 |
+
raise ValueError(
|
| 387 |
+
"Please specify a valid `data` object - either a `str` with a name or a `Dataset` object."
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
def prepare_data(self, data: Dataset, input_column: str, label_column: str, *args, **kwargs):
|
| 391 |
+
"""
|
| 392 |
+
Prepare data.
|
| 393 |
+
|
| 394 |
+
Args:
|
| 395 |
+
data ([`Dataset`]):
|
| 396 |
+
Specifies the dataset we will run evaluation on.
|
| 397 |
+
input_column (`str`, defaults to `"text"`):
|
| 398 |
+
The name of the column containing the text feature in the dataset specified by `data`.
|
| 399 |
+
second_input_column(`str`, *optional*):
|
| 400 |
+
The name of the column containing the second text feature if there is one. Otherwise, set to `None`.
|
| 401 |
+
label_column (`str`, defaults to `"label"`):
|
| 402 |
+
The name of the column containing the labels in the dataset specified by `data`.
|
| 403 |
+
Returns:
|
| 404 |
+
`dict`: metric inputs.
|
| 405 |
+
`list`: pipeline inputs.
|
| 406 |
+
|
| 407 |
+
Example:
|
| 408 |
+
|
| 409 |
+
```py
|
| 410 |
+
>>> from evaluate import evaluator
|
| 411 |
+
>>> from datasets import load_dataset
|
| 412 |
+
|
| 413 |
+
>>> ds = load_dataset("rotten_tomatoes", split="train")
|
| 414 |
+
>>> evaluator("text-classification").prepare_data(ds, input_column="text", second_input_column=None, label_column="label")
|
| 415 |
+
```
|
| 416 |
+
"""
|
| 417 |
+
|
| 418 |
+
self.check_required_columns(data, {"input_column": input_column, "label_column": label_column})
|
| 419 |
+
|
| 420 |
+
return {"references": data[label_column]}, DatasetColumn(data, input_column)
|
| 421 |
+
|
| 422 |
+
def prepare_pipeline(
|
| 423 |
+
self,
|
| 424 |
+
model_or_pipeline: Union[str, "Pipeline", Callable, "PreTrainedModel", "TFPreTrainedModel"], # noqa: F821
|
| 425 |
+
tokenizer: Union["PreTrainedTokenizerBase", "FeatureExtractionMixin"] = None, # noqa: F821
|
| 426 |
+
feature_extractor: Union["PreTrainedTokenizerBase", "FeatureExtractionMixin"] = None, # noqa: F821
|
| 427 |
+
device: int = None,
|
| 428 |
+
):
|
| 429 |
+
"""
|
| 430 |
+
Prepare pipeline.
|
| 431 |
+
|
| 432 |
+
Args:
|
| 433 |
+
model_or_pipeline (`str` or [`~transformers.Pipeline`] or `Callable` or [`~transformers.PreTrainedModel`] or [`~transformers.TFPreTrainedModel`], defaults to `None`):
|
| 434 |
+
If the argument in not specified, we initialize the default pipeline for the task. If the argument is of the type `str` or
|
| 435 |
+
is a model instance, we use it to initialize a new [`~transformers.Pipeline`] with the given model. Otherwise we assume the
|
| 436 |
+
argument specifies a pre-initialized pipeline.
|
| 437 |
+
preprocessor ([`~transformers.PreTrainedTokenizerBase`] or [`~transformers.FeatureExtractionMixin`], *optional*, defaults to `None`):
|
| 438 |
+
Argument can be used to overwrite a default preprocessor if `model_or_pipeline` represents a model for
|
| 439 |
+
which we build a pipeline. If `model_or_pipeline` is `None` or a pre-initialized pipeline, we ignore
|
| 440 |
+
this argument.
|
| 441 |
+
Returns:
|
| 442 |
+
The initialized pipeline.
|
| 443 |
+
|
| 444 |
+
Example:
|
| 445 |
+
|
| 446 |
+
```py
|
| 447 |
+
>>> from evaluate import evaluator
|
| 448 |
+
>>> evaluator("text-classification").prepare_pipeline(model_or_pipeline="distilbert-base-uncased")
|
| 449 |
+
```
|
| 450 |
+
"""
|
| 451 |
+
|
| 452 |
+
if device is None:
|
| 453 |
+
device = self._infer_device()
|
| 454 |
+
|
| 455 |
+
if (
|
| 456 |
+
isinstance(model_or_pipeline, str)
|
| 457 |
+
or isinstance(model_or_pipeline, transformers.PreTrainedModel)
|
| 458 |
+
or isinstance(model_or_pipeline, transformers.TFPreTrainedModel)
|
| 459 |
+
):
|
| 460 |
+
pipe = pipeline(
|
| 461 |
+
self.task,
|
| 462 |
+
model=model_or_pipeline,
|
| 463 |
+
tokenizer=tokenizer,
|
| 464 |
+
feature_extractor=feature_extractor,
|
| 465 |
+
device=device,
|
| 466 |
+
)
|
| 467 |
+
else:
|
| 468 |
+
if model_or_pipeline is None:
|
| 469 |
+
pipe = pipeline(self.task, device=device)
|
| 470 |
+
else:
|
| 471 |
+
pipe = model_or_pipeline
|
| 472 |
+
if tokenizer is not None and feature_extractor is not None:
|
| 473 |
+
logger.warning("Ignoring the value of the preprocessor argument (`tokenizer` or `feature_extractor`).")
|
| 474 |
+
if (pipe.task != self.task) and not (self.task == "translation" and pipe.task.startswith("translation")):
|
| 475 |
+
raise ValueError(
|
| 476 |
+
f"Incompatible `model_or_pipeline`. Please specify `model_or_pipeline` compatible with the `{self.task}` task."
|
| 477 |
+
)
|
| 478 |
+
return pipe
|
| 479 |
+
|
| 480 |
+
def prepare_metric(self, metric: Union[str, EvaluationModule]):
|
| 481 |
+
"""
|
| 482 |
+
Prepare metric.
|
| 483 |
+
|
| 484 |
+
Args:
|
| 485 |
+
metric (`str` or [`EvaluationModule`], defaults to `None`):
|
| 486 |
+
Specifies the metric we use in evaluator. If it is of type `str`, we treat it as the metric name, and
|
| 487 |
+
load it. Otherwise we assume it represents a pre-loaded metric.
|
| 488 |
+
|
| 489 |
+
Returns:
|
| 490 |
+
The loaded metric.
|
| 491 |
+
|
| 492 |
+
Example:
|
| 493 |
+
|
| 494 |
+
```py
|
| 495 |
+
>>> from evaluate import evaluator
|
| 496 |
+
>>> evaluator("text-classification").prepare_metric("accuracy")
|
| 497 |
+
```
|
| 498 |
+
"""
|
| 499 |
+
# Prepare metric.
|
| 500 |
+
if metric is None:
|
| 501 |
+
if self.default_metric_name is None:
|
| 502 |
+
raise ValueError(
|
| 503 |
+
"`Evaluator` doesn't specify a default metric. Please specify a valid `metric` argument."
|
| 504 |
+
)
|
| 505 |
+
metric = load(self.default_metric_name)
|
| 506 |
+
elif isinstance(metric, str):
|
| 507 |
+
metric = load(metric)
|
| 508 |
+
|
| 509 |
+
return metric
|
| 510 |
+
|
| 511 |
+
def call_pipeline(self, pipe, *args, **kwargs):
|
| 512 |
+
start_time = perf_counter()
|
| 513 |
+
pipe_output = pipe(*args, **kwargs, **self.PIPELINE_KWARGS)
|
| 514 |
+
end_time = perf_counter()
|
| 515 |
+
return pipe_output, self._compute_time_perf(start_time, end_time, len(pipe_output))
|
| 516 |
+
|
| 517 |
+
def compute_metric(
|
| 518 |
+
self,
|
| 519 |
+
metric: EvaluationModule,
|
| 520 |
+
metric_inputs: Dict,
|
| 521 |
+
strategy: Literal["simple", "bootstrap"] = "simple",
|
| 522 |
+
confidence_level: float = 0.95,
|
| 523 |
+
n_resamples: int = 9999,
|
| 524 |
+
random_state: Optional[int] = None,
|
| 525 |
+
):
|
| 526 |
+
"""Compute and return metrics."""
|
| 527 |
+
result = metric.compute(**metric_inputs, **self.METRIC_KWARGS)
|
| 528 |
+
|
| 529 |
+
if strategy == "bootstrap":
|
| 530 |
+
metric_keys = result.keys()
|
| 531 |
+
bootstrap_dict = self._compute_confidence_interval(
|
| 532 |
+
metric,
|
| 533 |
+
metric_inputs,
|
| 534 |
+
metric_keys,
|
| 535 |
+
confidence_level,
|
| 536 |
+
n_resamples,
|
| 537 |
+
random_state,
|
| 538 |
+
)
|
| 539 |
+
for key in metric_keys:
|
| 540 |
+
bootstrap_dict[key]["score"] = result[key]
|
| 541 |
+
|
| 542 |
+
return bootstrap_dict
|
| 543 |
+
|
| 544 |
+
return result
|
Prism/LLaDA/LLaDA_Prism/.venv/lib/python3.12/site-packages/evaluate/evaluator/image_classification.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 The HuggingFace Evaluate Authors.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
from numbers import Number
|
| 16 |
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Union
|
| 17 |
+
|
| 18 |
+
from datasets import Dataset
|
| 19 |
+
from typing_extensions import Literal
|
| 20 |
+
|
| 21 |
+
from ..module import EvaluationModule
|
| 22 |
+
from ..utils.file_utils import add_end_docstrings, add_start_docstrings
|
| 23 |
+
from .base import EVALUATOR_COMPUTE_RETURN_DOCSTRING, EVALUTOR_COMPUTE_START_DOCSTRING, Evaluator
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
if TYPE_CHECKING:
|
| 27 |
+
from transformers import FeatureExtractionMixin, Pipeline, PreTrainedModel, PreTrainedTokenizer, TFPreTrainedModel
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
TASK_DOCUMENTATION = r"""
|
| 31 |
+
Examples:
|
| 32 |
+
```python
|
| 33 |
+
>>> from evaluate import evaluator
|
| 34 |
+
>>> from datasets import load_dataset
|
| 35 |
+
>>> task_evaluator = evaluator("image-classification")
|
| 36 |
+
>>> data = load_dataset("beans", split="test[:40]")
|
| 37 |
+
>>> results = task_evaluator.compute(
|
| 38 |
+
>>> model_or_pipeline="nateraw/vit-base-beans",
|
| 39 |
+
>>> data=data,
|
| 40 |
+
>>> label_column="labels",
|
| 41 |
+
>>> metric="accuracy",
|
| 42 |
+
>>> label_mapping={'angular_leaf_spot': 0, 'bean_rust': 1, 'healthy': 2},
|
| 43 |
+
>>> strategy="bootstrap"
|
| 44 |
+
>>> )
|
| 45 |
+
```
|
| 46 |
+
"""
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class ImageClassificationEvaluator(Evaluator):
|
| 50 |
+
"""
|
| 51 |
+
Image classification evaluator.
|
| 52 |
+
This image classification evaluator can currently be loaded from [`evaluator`] using the default task name
|
| 53 |
+
`image-classification`.
|
| 54 |
+
Methods in this class assume a data format compatible with the [`ImageClassificationPipeline`].
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
PIPELINE_KWARGS = {}
|
| 58 |
+
|
| 59 |
+
def __init__(self, task="image-classification", default_metric_name=None):
|
| 60 |
+
super().__init__(task, default_metric_name=default_metric_name)
|
| 61 |
+
|
| 62 |
+
def predictions_processor(self, predictions, label_mapping):
|
| 63 |
+
pred_label = [max(pred, key=lambda x: x["score"])["label"] for pred in predictions]
|
| 64 |
+
pred_label = [label_mapping[pred] if label_mapping is not None else pred for pred in pred_label]
|
| 65 |
+
|
| 66 |
+
return {"predictions": pred_label}
|
| 67 |
+
|
| 68 |
+
@add_start_docstrings(EVALUTOR_COMPUTE_START_DOCSTRING)
|
| 69 |
+
@add_end_docstrings(EVALUATOR_COMPUTE_RETURN_DOCSTRING, TASK_DOCUMENTATION)
|
| 70 |
+
def compute(
|
| 71 |
+
self,
|
| 72 |
+
model_or_pipeline: Union[
|
| 73 |
+
str, "Pipeline", Callable, "PreTrainedModel", "TFPreTrainedModel" # noqa: F821
|
| 74 |
+
] = None,
|
| 75 |
+
data: Union[str, Dataset] = None,
|
| 76 |
+
subset: Optional[str] = None,
|
| 77 |
+
split: Optional[str] = None,
|
| 78 |
+
metric: Union[str, EvaluationModule] = None,
|
| 79 |
+
tokenizer: Optional[Union[str, "PreTrainedTokenizer"]] = None, # noqa: F821
|
| 80 |
+
feature_extractor: Optional[Union[str, "FeatureExtractionMixin"]] = None, # noqa: F821
|
| 81 |
+
strategy: Literal["simple", "bootstrap"] = "simple",
|
| 82 |
+
confidence_level: float = 0.95,
|
| 83 |
+
n_resamples: int = 9999,
|
| 84 |
+
device: int = None,
|
| 85 |
+
random_state: Optional[int] = None,
|
| 86 |
+
input_column: str = "image",
|
| 87 |
+
label_column: str = "label",
|
| 88 |
+
label_mapping: Optional[Dict[str, Number]] = None,
|
| 89 |
+
) -> Tuple[Dict[str, float], Any]:
|
| 90 |
+
|
| 91 |
+
"""
|
| 92 |
+
input_column (`str`, defaults to `"image"`):
|
| 93 |
+
The name of the column containing the images as PIL ImageFile in the dataset specified by `data`.
|
| 94 |
+
label_column (`str`, defaults to `"label"`):
|
| 95 |
+
The name of the column containing the labels in the dataset specified by `data`.
|
| 96 |
+
label_mapping (`Dict[str, Number]`, *optional*, defaults to `None`):
|
| 97 |
+
We want to map class labels defined by the model in the pipeline to values consistent with those
|
| 98 |
+
defined in the `label_column` of the `data` dataset.
|
| 99 |
+
"""
|
| 100 |
+
|
| 101 |
+
result = super().compute(
|
| 102 |
+
model_or_pipeline=model_or_pipeline,
|
| 103 |
+
data=data,
|
| 104 |
+
subset=subset,
|
| 105 |
+
split=split,
|
| 106 |
+
metric=metric,
|
| 107 |
+
tokenizer=tokenizer,
|
| 108 |
+
feature_extractor=feature_extractor,
|
| 109 |
+
strategy=strategy,
|
| 110 |
+
confidence_level=confidence_level,
|
| 111 |
+
n_resamples=n_resamples,
|
| 112 |
+
device=device,
|
| 113 |
+
random_state=random_state,
|
| 114 |
+
input_column=input_column,
|
| 115 |
+
label_column=label_column,
|
| 116 |
+
label_mapping=label_mapping,
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
return result
|