Skip to content

Commit

Permalink
Merge pull request #15 from portyanikhin/8-units-systems
Browse files Browse the repository at this point in the history
Added the ability to configure the units system using the config file
  • Loading branch information
portyanikhin authored May 25, 2023
2 parents b6aea84 + f7f7c72 commit 43a0648
Show file tree
Hide file tree
Showing 24 changed files with 825 additions and 166 deletions.
154 changes: 77 additions & 77 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pyfluids/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from .config import *
from .enums import *
from .fluids import *
from .humid_air import *
from .io import *

__all__ = enums.__all__ + fluids.__all__ + humid_air.__all__ + io.__all__
__all__ = (
config.__all__ + enums.__all__ + fluids.__all__ + humid_air.__all__ + io.__all__
)
11 changes: 11 additions & 0 deletions pyfluids/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from .pyfluids_config import *
from .pyfluids_config_builder import *
from .unit_converter import *
from .units_system import *

__all__ = (
pyfluids_config.__all__
+ pyfluids_config_builder.__all__
+ unit_converter.__all__
+ units_system.__all__
)
12 changes: 12 additions & 0 deletions pyfluids/config/pyfluids_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from dataclasses import dataclass

from .units_system import UnitsSystem

__all__ = ["PyFluidsConfig"]


@dataclass
class PyFluidsConfig:
"""PyFluids configuration."""

units_system: UnitsSystem = UnitsSystem.SIWithCelsiusAndPercents
110 changes: 110 additions & 0 deletions pyfluids/config/pyfluids_config_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from __future__ import annotations

import json
from configparser import ConfigParser
from os.path import abspath
from pathlib import Path

import tomli

from .pyfluids_config import PyFluidsConfig
from .singleton import Singleton
from .units_system import UnitsSystem

__all__ = ["PyFluidsConfigBuilder"]


# noinspection PyBroadException
class PyFluidsConfigBuilder(metaclass=Singleton):
"""PyFluids configuration builder."""

def __init__(self):
"""PyFluids configuration builder."""
self.__config: PyFluidsConfig | None = None
self.__config_names: list[str] = [
"pyfluids.ini",
"pyfluids.json",
"pyproject.toml",
"tox.ini",
]

@property
def __current_path(self) -> Path:
return Path(abspath(Path.cwd()))

@property
def __config_file(self) -> Path | None:
for root in (self.__current_path, *self.__current_path.parents):
for config_name in self.__config_names:
path = root / config_name
if path.is_file():
return path
return None

@property
def __config_data(self) -> str:
return self.__config_file.read_text(encoding="utf-8")

def build(self) -> PyFluidsConfig:
"""
Build PyFluids configuration.
If the configuration file is not found or an incorrect
configuration is found in the files "pyproject.toml" or "tox.ini",
returns the default configuration.
:raises ValueError: If configuration file is invalid.
"""
if self.__config is not None:
return self.__config
if self.__config_file is None:
return self.__create_default_config()
if self.__config_file.suffix == ".ini":
return self.__load_config_from_ini_file()
if self.__config_file.suffix == ".json":
return self.__load_config_from_json_file()
return self.__load_config_from_toml_file()

def _reset(self):
self.__config = None

def __create_default_config(self) -> PyFluidsConfig:
self.__config = PyFluidsConfig()
return self.__config

def __create_config_from_dict(self, config_dict: dict) -> PyFluidsConfig:
config_dict["units_system"] = UnitsSystem[config_dict["units_system"]]
self.__config = PyFluidsConfig(**config_dict)
return self.__config

def __load_config_from_ini_file(self) -> PyFluidsConfig:
try:
config_parser = ConfigParser()
config_parser.read(self.__config_file)
return self.__create_config_from_dict(dict(config_parser.items("pyfluids")))
except Exception:
if self.__config_file.name.startswith("pyfluids"):
self.__raise_invalid_config_exception()
return self.__create_default_config()

def __load_config_from_json_file(self) -> PyFluidsConfig:
try:
return self.__create_config_from_dict(
json.loads(self.__config_data)["pyfluids"]
)
except Exception:
self.__raise_invalid_config_exception()

def __load_config_from_toml_file(self) -> PyFluidsConfig:
try:
return self.__create_config_from_dict(
tomli.loads(self.__config_data)["tool"]["pyfluids"]
)
except Exception:
return self.__create_default_config()

def __raise_invalid_config_exception(self):
raise ValueError(
"Invalid PyFluids configuration! "
f"Check your configuration file: {self.__config_file}"
)
7 changes: 7 additions & 0 deletions pyfluids/config/singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Singleton(type):
_instances = {}

def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
62 changes: 62 additions & 0 deletions pyfluids/config/unit_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from .pyfluids_config import PyFluidsConfig
from .pyfluids_config_builder import PyFluidsConfigBuilder
from .units_system import UnitsSystem

__all__ = ["UnitConverter"]


class UnitConverter:
"""Unit converter."""

def __init__(self):
"""Unit converter."""
self.__config: PyFluidsConfig = PyFluidsConfigBuilder().build()

@property
def units_system(self) -> UnitsSystem:
"""Configured units system."""
return self.__config.units_system

def convert_temperature_from_si(self, value: float) -> float:
"""
Convert temperature from SI to configured units system.
:param value: Temperature value.
:return: Converted value.
"""
if self.units_system == UnitsSystem.SI:
return value
return value - 273.15

def convert_temperature_to_si(self, value: float) -> float:
"""
Convert temperature from configured units system to SI.
:param value: Temperature value.
:return: Converted value.
"""
if self.units_system == UnitsSystem.SI:
return value
return value + 273.15

def convert_decimal_fraction_from_si(self, value: float) -> float:
"""
Convert decimal fraction from SI to configured units system.
:param value: Decimal fraction value.
:return: Converted value.
"""
if self.units_system == UnitsSystem.SIWithCelsiusAndPercents:
return value * 1e2
return value

def convert_decimal_fraction_to_si(self, value: float) -> float:
"""
Convert decimal fraction from configured units system to SI.
:param value: Decimal fraction value.
:return: Converted value.
"""
if self.units_system == UnitsSystem.SIWithCelsiusAndPercents:
return value * 1e-2
return value
17 changes: 17 additions & 0 deletions pyfluids/config/units_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from enum import Enum

__all__ = ["UnitsSystem"]


class UnitsSystem(Enum):
"""List of available units systems."""

SI = "SI"
SIWithCelsius = "SIWithCelsius"
SIWithCelsiusAndPercents = "SIWithCelsiusAndPercents"

def __repr__(self) -> str:
return self.name

def __str__(self) -> str:
return self.name
20 changes: 14 additions & 6 deletions pyfluids/enums/fluids_list.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from enum import Enum

from .mix import Mix
from ..config import UnitConverter


__all__ = ["FluidsList"]

Expand Down Expand Up @@ -409,10 +411,10 @@ def __init__(
fraction_max,
)

def __repr__(self):
def __repr__(self) -> str:
return self.name

def __str__(self):
def __str__(self) -> str:
return self.name

@property
Expand All @@ -437,10 +439,16 @@ def mix_type(self) -> Mix:

@property
def fraction_min(self) -> float:
"""Minimum possible fraction [%]."""
return self.__fraction_min * 1e2
"""
Minimum possible fraction
[by default, %; you can change this using the configuration file].
"""
return UnitConverter().convert_decimal_fraction_from_si(self.__fraction_min)

@property
def fraction_max(self) -> float:
"""Maximum possible fraction [%]."""
return self.__fraction_max * 1e2
"""
Maximum possible fraction
[by default, %; you can change this using the configuration file].
"""
return UnitConverter().convert_decimal_fraction_from_si(self.__fraction_max)
4 changes: 2 additions & 2 deletions pyfluids/enums/mix.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ class Mix(Enum):
Mass = "Mass-based mixture"
Volume = "Volume-based mixture"

def __repr__(self):
def __repr__(self) -> str:
return self.name

def __str__(self):
def __str__(self) -> str:
return self.name
4 changes: 2 additions & 2 deletions pyfluids/enums/phases.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class Phases(Enum):
Unknown = CoolProp.iphase_unknown
NotImposed = CoolProp.iphase_not_imposed

def __repr__(self):
def __repr__(self) -> str:
return self.name

def __str__(self):
def __str__(self) -> str:
return self.name
Loading

0 comments on commit 43a0648

Please sign in to comment.