<commit_before># -*- coding: utf-8 -*-

# Copyright 2009-2019, <NAME>, <EMAIL>

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""Calculations for the position of the sun and moon.

The :mod:`astral` package provides the means to calculate the following times of the sun

* dawn
* sunrise
* noon
* midnight
* sunset
* dusk
* daylight
* night
* twilight
* blue hour
* golden hour
* rahukaalam

plus solar azimuth and elevation at a specific latitude/longitude.
It can also calculate the moon phase for a specific date.

The package also provides a self contained geocoder to turn a small set of
location names into timezone, latitude and longitude. The lookups
can be perfomed using the :func:`~astral.geocoder.lookup` function defined in
:mod:`astral.geocoder`

.. note::

   The `Astral` and `GoogleGeocoder` classes from earlier versions have been
   removed.
"""

import datetime
import re
from dataclasses import dataclass
from enum import Enum
from math import fabs
from typing import Any, Union

try:
    import pytz
except ImportError:
    raise ImportError(("The astral module requires the pytz module to be available."))


__all__ = [
    "Depression",
    "SunDirection",
    "Observer",
    "LocationInfo",
    "now",
    "today",
    "dms_to_float",
]

__version__ = "2.0-alpha"
__author__ = "Simon Kennedy <<EMAIL>>"


def now(tzinfo: datetime.tzinfo = pytz.utc) -> datetime.datetime:
    """Returns the current time in the specified time zone"""
    return pytz.utc.localize(datetime.datetime.utcnow()).astimezone(tzinfo)


def today(tzinfo: datetime.tzinfo = pytz.utc) -> datetime.date:
    """Returns the current date in the specified time zone"""
    return now(tzinfo).date()


def dms_to_float(dms: Union[str, float], limit: float) -> float:
    """Converts as string of the form `degrees°minutes'seconds"[N|S|E|W]`,
    or a float encoded as a string, to a float

    N and E return positive values
    S and W return negative values

    Args:
        dms: string to convert
        limit: Limit the value between 0 and this parameter

    Returns:
        The number of degrees as a float
    """

    try:
        res = float(dms)
    except (ValueError, TypeError):
        m = re.match(_dms_re, str(dms), flags=re.IGNORECASE)
        if m:
            deg = m.group("deg") or 0.0
            min_ = m.group("min") or 0.0
            sec = m.group("sec") or 0.0
            dir_ = m.group("dir") or "E"

            res = float(deg)
            if min_:
                res += float(min_) / 60
            if sec:
                res += float(sec) / 3600

            if dir_.upper() in ["S", "W"]:
                res = -res
        else:
            raise ValueError("Unable to convert degrees/minutes/seconds to float")

    if res > limit:
        res = limit
    elif res < -limit:
        res = -limit

    return res


class Depression(Enum):
    """The depression angle in degrees for the dawn/dusk calculations"""

    CIVIL: float = 6.0
    NAUTICAL: float = 12.0
    ASTRONOMICAL: float = 18.0


class SunDirection(Enum):
    """Direction of the sun either RISING or SETTING"""

    RISING = 1
    SETTING = -1


@dataclass
class Observer:
    """Defines the location of an observer on Earth.

    Latitude and longitude can be set either as a float or as a string. For strings they must
    be of the form

        degrees°minutes'seconds"[N|S|E|W] e.g. 51°31'N

    `minutes’` & `seconds”` are optional.

    Elevations are either

    * A float that is the elevation in metres above a location, if the nearest
      obscuring feature is the horizon
    * or a tuple of the elevation in metres and the distance in metres to the
      nearest obscuring feature.

    Args:
        latitude:   Latitude - Northern latitudes should be positive
        longitude:  Longitude - Eastern longitudes should be positive
        elevation:  Elevation in metres above sea level.
    """

    latitude: float = 51.4733
    longitude: float = -0.00088
    elevation: float = 24.0

    def __setattr__(self, name: str, value: Union[float, str]):
        if name == "latitude":
            value = dms_to_float(value, 90.0)
        elif name == "longitude":
            value = dms_to_float(value, 180.0)
        elif name == "elevation":
            if isinstance(value, tuple):
                value = (float(value[0]), float(value[1]))
            else:
                value = float(value)
        super(Observer, self).__setattr__(name, value)


@dataclass
class LocationInfo:
    """Defines a location on Earth.

    Latitude and longitude can be set either as a float or as a string. For strings they must
    be of the form

        degrees°minutes'seconds"[N|S|E|W] e.g. 51°31'N

    `minutes’` & `seconds”` are optional.

    Args:<commit_msg>No argument super<commit_after># -*- coding: utf-8 -*-

# Copyright 2009-2019, <NAME>, <EMAIL>

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""Calculations for the position of the sun and moon.

The :mod:`astral` package provides the means to calculate the following times of the sun

* dawn
* sunrise
* noon
* midnight
* sunset
* dusk
* daylight
* night
* twilight
* blue hour
* golden hour
* rahukaalam

plus solar azimuth and elevation at a specific latitude/longitude.
It can also calculate the moon phase for a specific date.

The package also provides a self contained geocoder to turn a small set of
location names into timezone, latitude and longitude. The lookups
can be perfomed using the :func:`~astral.geocoder.lookup` function defined in
:mod:`astral.geocoder`

.. note::

   The `Astral` and `GoogleGeocoder` classes from earlier versions have been
   removed.
"""

import datetime
import re
from dataclasses import dataclass
from enum import Enum
from math import fabs
from typing import Any, Union

try:
    import pytz
except ImportError:
    raise ImportError(("The astral module requires the pytz module to be available."))


__all__ = [
    "Depression",
    "SunDirection",
    "Observer",
    "LocationInfo",
    "now",
    "today",
    "dms_to_float",
]

__version__ = "2.0-alpha"
__author__ = "<NAME> <<EMAIL>>"


def now(tzinfo: datetime.tzinfo = pytz.utc) -> datetime.datetime:
    """Returns the current time in the specified time zone"""
    return pytz.utc.localize(datetime.datetime.utcnow()).astimezone(tzinfo)


def today(tzinfo: datetime.tzinfo = pytz.utc) -> datetime.date:
    """Returns the current date in the specified time zone"""
    return now(tzinfo).date()


def dms_to_float(dms: Union[str, float], limit: float) -> float:
    """Converts as string of the form `degrees°minutes'seconds"[N|S|E|W]`,
    or a float encoded as a string, to a float

    N and E return positive values
    S and W return negative values

    Args:
        dms: string to convert
        limit: Limit the value between 0 and this parameter

    Returns:
        The number of degrees as a float
    """

    try:
        res = float(dms)
    except (ValueError, TypeError):
        m = re.match(_dms_re, str(dms), flags=re.IGNORECASE)
        if m:
            deg = m.group("deg") or 0.0
            min_ = m.group("min") or 0.0
            sec = m.group("sec") or 0.0
            dir_ = m.group("dir") or "E"

            res = float(deg)
            if min_:
                res += float(min_) / 60
            if sec:
                res += float(sec) / 3600

            if dir_.upper() in ["S", "W"]:
                res = -res
        else:
            raise ValueError("Unable to convert degrees/minutes/seconds to float")

    if res > limit:
        res = limit
    elif res < -limit:
        res = -limit

    return res


class Depression(Enum):
    """The depression angle in degrees for the dawn/dusk calculations"""

    CIVIL: float = 6.0
    NAUTICAL: float = 12.0
    ASTRONOMICAL: float = 18.0


class SunDirection(Enum):
    """Direction of the sun either RISING or SETTING"""

    RISING = 1
    SETTING = -1


@dataclass
class Observer:
    """Defines the location of an observer on Earth.

    Latitude and longitude can be set either as a float or as a string. For strings they must
    be of the form

        degrees°minutes'seconds"[N|S|E|W] e.g. 51°31'N

    `minutes’` & `seconds”` are optional.

    Elevations are either

    * A float that is the elevation in metres above a location, if the nearest
      obscuring feature is the horizon
    * or a tuple of the elevation in metres and the distance in metres to the
      nearest obscuring feature.

    Args:
        latitude:   Latitude - Northern latitudes should be positive
        longitude:  Longitude - Eastern longitudes should be positive
        elevation:  Elevation in metres above sea level.
    """

    latitude: float = 51.4733
    longitude: float = -0.00088
    elevation: float = 24.0

    def __setattr__(self, name: str, value: Union[float, str]):
        if name == "latitude":
            value = dms_to_float(value, 90.0)
        elif name == "longitude":
            value = dms_to_float(value, 180.0)
        elif name == "elevation":
            if isinstance(value, tuple):
                value = (float(value[0]), float(value[1]))
            else:
                value = float(value)
        super().__setattr__(name, value)


@dataclass
class LocationInfo:
    """Defines a location on Earth.

    Latitude and longitude can be set either as a float or as a string. For strings they must
    be of the form

        degrees°minutes'seconds"[N|S|E|W] e.g. 51°31'N

    `minutes’` & `seconds”` are optional.

    Args:
{'fraction_non_alphanumeric': 0.09361097964978703, 'fraction_numerical': 0.013251301467108376, 'mean_word_length': 2.6371772805507745, 'pattern_counts': {'":': 6, '<': 14, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2061907', 'n_tokens_mistral': 3296, 'n_tokens_neox': 3100, 'n_words': 1223}