Skip to content

Commit

Permalink
Merge pull request #626 from openego/features/adjust-db-interface
Browse files Browse the repository at this point in the history
Features/adjust db interface
  • Loading branch information
ClaraBuettner authored Sep 25, 2023
2 parents 86142b9 + 9cb4e5f commit e16bdd3
Show file tree
Hide file tree
Showing 5 changed files with 227 additions and 4 deletions.
2 changes: 1 addition & 1 deletion etrago/tools/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import pyomo.environ as po

if "READTHEDOCS" not in os.environ:
from egoio.tools import db
from etrago.tools import db

logger = logging.getLogger(__name__)

Expand Down
222 changes: 222 additions & 0 deletions etrago/tools/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# -*- coding: utf-8 -*-
# Copyright 2016-2018 Flensburg University of Applied Sciences,
# Europa-Universität Flensburg,
# Centre for Sustainable Energy Systems,
# DLR-Institute for Networked Energy Systems

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import configparser as cp
import getpass
import os

from sqlalchemy import create_engine
import keyring
import oedialect


def readcfg(filepath, section):
"""
Reads the configuration file. If section is not available, calls
create_oedb_config_file to add the new section to an existing config.ini.
Parameters
----------
filepath : str
Absolute path of config file including the filename itself
section : str
Section in config file which contains connection details
Returns
-------
cfg : configparser.ConfigParser
Used for configuration file parser language.
"""

cfg = cp.ConfigParser()
cfg.read(filepath)

if not cfg.has_section(section):
print(
'The section "{sec}" is not in the config file {file}.'.format(
sec=section, file=filepath
)
)
cfg = create_oedb_config_file(filepath, section)

return cfg


def get_connection_details(section):
"""
Asks the user for the database connection details and returns them as a
ConfigParser-object.
Parameters
----------
None
Returns
-------
cfg : configparser.ConfigParser
Used for configuration file parser language.
"""
print("Please enter your connection details:")
dialect = (
input("Enter input value for `dialect` (default: psycopg2): ")
or "psycopg2"
)
username = input("Enter value for `username`: ")
database = input("Enter value for `database`: ")
host = input("Enter value for `host`: ")
port = input("Enter value for `port` (default: 5432): ") or "5432"

cfg = cp.ConfigParser()
cfg.add_section(section)
cfg.set(section, "dialect", dialect)
cfg.set(section, "username", username)
cfg.set(section, "host", host)
cfg.set(section, "port", port)
cfg.set(section, "database", database)
pw = getpass.getpass(
prompt="Enter your password/token to "
"store it in "
"keyring: ".format(database=section)
)
keyring.set_password(section, cfg.get(section, "username"), pw)

return cfg


def create_oedb_config_file(filepath, section="oep"):
"""
Parameters
----------
filepath : str
Absolute path of config file including the filename itself
section : str
Section in config file which contains connection details
Returns
-------
cfg : configparser.ConfigParser
Used for configuration file parser language.
"""

cfg = get_connection_details(section)

print(
"Do you want to store the connection details in the config file {file} ?".format(
file=filepath
)
)
choice = ""
while choice not in ["y", "n"]:
choice = input("(y/n): ")

if choice == "y":
# create egoio dir if not existent
base_path = os.path.split(filepath)[0]
if not os.path.isdir(base_path):
os.mkdir(base_path)
print("The directory {path} was created.".format(path=base_path))

with open(filepath, "a") as configfile:
cfg.write(configfile)
pass

print(
'Template {0} with section "{1}" created.\nYou can manually edit'
" the config file.".format(filepath, section)
)
else:
pass

return cfg


def connection(filepath=None, section="oep", readonly=False):
"""
Instantiate a database connection (for the use with SQLAlchemy).
The keyword argument `filepath` specifies the location of the config file
that contains database connection information. If not given, the default
of `~/.etrago_database/config.ini` applies.
Parameters
----------
filepath : str
Absolute path of config file including the filename itself
section : str
Section in config file containing database connection parameters.
Default: 'oep'.
readonly : bool
Set this option to True for creating a read-only and passwordless
engine for accessing the open energy platform.
Default: False.
Returns
-------
conn : sqlalchemy.engine
SQLalchemy engine object containing the connection details
"""

if readonly:
conn = create_engine("postgresql+oedialect://openenergy-platform.org")
else:
# define default filepath if not provided
if filepath is None:
filepath = os.path.join(
os.path.expanduser("~"), ".etrago_database", "config.ini"
)

# does the file exist?
if not os.path.isfile(filepath):
print(
"DB config file {file} not found. "
"This might be the first run of the tool. ".format(
file=filepath
)
)
cfg = create_oedb_config_file(filepath, section=section)
else:
cfg = readcfg(filepath, section)

try:
pw = cfg.get(section, "password")
except:
pw = keyring.get_password(section, cfg.get(section, "username"))
if pw is None:
pw = getpass.getpass(
prompt='No password found for database "{db}". '
"Enter your password to "
"store it in keyring: ".format(
db=cfg.get(section, "database")
)
)
keyring.set_password(section, cfg.get(section, "username"), pw)

# establish connection and return it
conn = create_engine(
"postgresql+{dialect}://{user}:{password}@{host}:{port}/{db}".format(
dialect=cfg.get(section, "dialect", fallback="psycopg2"),
user=cfg.get(section, "username"),
password=pw,
host=cfg.get(section, "host"),
port=cfg.get(section, "port"),
db=cfg.get(section, "database"),
)
)

return conn
2 changes: 1 addition & 1 deletion etrago/tools/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import pandas as pd

if "READTHEDOCS" not in os.environ:
from egoio.tools import db
from etrago.tools import db

from etrago import __version__
from etrago.cluster.disaggregation import run_disaggregation
Expand Down
3 changes: 2 additions & 1 deletion etrago/tools/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@
import sqlalchemy.exc

if "READTHEDOCS" not in os.environ:
from egoio.tools import db
from shapely.geometry import Point
import geopandas as gpd

from etrago.tools import db

logger = logging.getLogger(__name__)


Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def read(*names, **kwargs):
packages=find_packages(),
include_package_data=True,
install_requires=[
"egoio == 0.4.7",
"geoalchemy2 >= 0.3.0",
"geopandas",
"keyring",
"loguru",
"matplotlib >= 3.0.3",
"oedialect",
Expand Down

0 comments on commit e16bdd3

Please sign in to comment.