-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose env var handling to python #856
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#ifndef PHARE_CORE_ENV_HPP | ||
#define PHARE_CORE_ENV_HPP | ||
|
||
// Single source for handling env vars | ||
|
||
#include <array> | ||
#include <cstdint> | ||
#include <optional> | ||
#include <string_view> | ||
#include <unordered_map> | ||
#include "core/utilities/types.hpp" | ||
#include "core/utilities/mpi_utils.hpp" | ||
|
||
namespace PHARE::env | ||
{ | ||
|
||
struct Var | ||
{ | ||
using value_type = std::string; | ||
using results_type = std::unordered_map<std::string, std::string>; | ||
auto constexpr static noop_results = [](Var const&) { return results_type{}; }; | ||
|
||
std::string_view const id; | ||
std::string_view const desc; | ||
std::vector<std::pair<std::string_view, std::string_view>> const options; | ||
|
||
std::optional<value_type> const _default = std::nullopt; | ||
std::function<results_type(Var const&)> const _results = noop_results; | ||
std::optional<value_type> const v = get(); | ||
results_type const results = _results(*this); | ||
|
||
std::optional<value_type> get() const | ||
{ | ||
std::string _id{id}; | ||
if (_default) | ||
return core::get_env(_id, *_default); | ||
return core::get_env(_id); | ||
} | ||
auto const& operator()() const { return v; } | ||
auto const& operator()(std::string const& s) const { return results.at(s); } | ||
auto const& operator()(std::string const& s, std::string const& default_) const | ||
{ | ||
if (results.count(s)) | ||
return results.at(s); | ||
return default_; | ||
} | ||
bool exists() const { return v != std::nullopt; } | ||
operator bool() const { return exists(); } | ||
}; | ||
Comment on lines
+17
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using explicit constructors for The struct Var
{
explicit Var(std::string_view id, std::string_view desc, std::vector<std::pair<std::string_view, std::string_view>> options, std::optional<value_type> def = std::nullopt, std::function<results_type(Var const&)> res = noop_results)
: id{id}, desc{desc}, options{std::move(options)}, _default{def}, _results{res}, v{get()}, results{_results(*this)}
{}
}; |
||
|
||
} // namespace PHARE::env | ||
|
||
namespace PHARE | ||
{ | ||
class Env | ||
{ | ||
public: | ||
template<typename T> | ||
using map_t = std::unordered_map<std::string, T const* const>; | ||
|
||
static Env& INSTANCE() | ||
{ | ||
if (!self) | ||
self = std::make_unique<Env>(); | ||
return *self; | ||
} | ||
static auto& reinit() { return *(self = std::make_unique<Env>()); } | ||
|
||
env::Var const PHARE_LOG{ | ||
"PHARE_LOG", | ||
"Write logs to $CWD/.log", | ||
{{{"RANK_FILES", "Write logs $CWD/.log, a file per rank"}, | ||
{"DATETIME_FILES", "Write logs $CWD/.log, filename per rank and datetime"}, | ||
{"NONE", "print normally to std::cout"}}}, | ||
std::nullopt, | ||
[](auto const& self) { | ||
std::string static const file_key = "PHARE_LOG_FILE"; | ||
typename env::Var::results_type map; | ||
if (auto const& opt = self()) | ||
{ | ||
auto const& val = *opt; | ||
if (val == "RANK_FILES") | ||
map[file_key] = ".log/" + std::to_string(core::mpi::rank()) + ".out"; | ||
else if (val == "DATETIME_FILES") | ||
{ | ||
auto date_time = core::mpi::date_time(); | ||
auto rank = std::to_string(core::mpi::rank()); | ||
auto size = std::to_string(core::mpi::size()); | ||
map[file_key] = ".log/" + date_time + "_" + rank + "_of_" + size + ".out"; | ||
} | ||
else if (val != "NONE") | ||
throw std::runtime_error("PHARE_LOG invalid type, valid keys are " | ||
"RANK_FILES/DATETIME_FILES/NONE"); | ||
} | ||
return map; | ||
} // | ||
}; | ||
Comment on lines
+69
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add validation for The env::Var const PHARE_LOG{
"PHARE_LOG",
"Write logs to $CWD/.log",
{{{"RANK_FILES", "Write logs $CWD/.log, a file per rank"},
{"DATETIME_FILES", "Write logs $CWD/.log, filename per rank and datetime"},
{"NONE", "print normally to std::cout"}}},
std::nullopt,
[](auto const& self) {
std::string static const file_key = "PHARE_LOG_FILE";
typename env::Var::results_type map;
if (auto const& opt = self())
{
auto const& val = *opt;
if (val == "RANK_FILES")
map[file_key] = ".log/" + std::to_string(core::mpi::rank()) + ".out";
else if (val == "DATETIME_FILES")
{
auto date_time = core::mpi::date_time();
auto rank = std::to_string(core::mpi::rank());
auto size = std::to_string(core::mpi::size());
map[file_key] = ".log/" + date_time + "_" + rank + "_of_" + size + ".out";
}
else if (val != "NONE")
throw std::runtime_error("PHARE_LOG invalid type, valid keys are "
"RANK_FILES/DATETIME_FILES/NONE");
}
return map;
} //
}; |
||
env::Var const PHARE_SCOPE_TIMING{ | ||
"PHARE_SCOPE_TIMING", "Enable function scope timing", {{{"1", "ON"}, {"0", "OFF"}}}, "0"}; | ||
|
||
map_t<env::Var> const vars = {{ | ||
{"PHARE_LOG", &PHARE_LOG}, | ||
{"PHARE_SCOPE_TIMING", &PHARE_SCOPE_TIMING}, | ||
}}; | ||
|
||
auto& operator()(std::string const& s) const | ||
{ | ||
assert(vars.count(s)); | ||
return *vars.at(s); | ||
} | ||
|
||
private: | ||
static inline std::unique_ptr<Env> self = nullptr; | ||
}; | ||
Comment on lines
+55
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider making The class Env
{
public:
static Env& INSTANCE()
{
static Env instance;
return instance;
}
// Delete copy constructor and assignment operator
Env(const Env&) = delete;
Env& operator=(const Env&) = delete;
// Other methods and member variables...
}; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is a singleton, just in this case we can reset the internal memory easily There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @PhilipDeegan, thank you for the clarification. Your approach to implementing the singleton pattern while allowing for the internal memory to be reset provides the necessary flexibility for reinitialization scenarios. This design ensures that the |
||
|
||
} // namespace PHARE | ||
|
||
#endif /* PHARE_CORE_ERRORS_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,8 @@ inline bool is_init() | |
return flag > 0; | ||
} | ||
|
||
|
||
|
||
template<typename Data> | ||
NO_DISCARD auto mpi_type_for() | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -195,6 +195,18 @@ namespace core | |
T var; | ||
}; | ||
|
||
template<typename T> | ||
NO_DISCARD T from_string(std::string const& s) | ||
{ | ||
T t; | ||
std::stringstream ss(s); | ||
ss >> t; | ||
ss >> t; | ||
if (ss.fail()) | ||
throw std::runtime_error("PHARE::core::from_string - Conversion failed: " + s); | ||
return t; | ||
} | ||
|
||
template<typename T> | ||
NO_DISCARD std::string to_string_with_precision(T const& a_value, std::size_t const len) | ||
{ | ||
|
@@ -246,6 +258,24 @@ namespace core | |
} | ||
|
||
|
||
template<typename T> | ||
NO_DISCARD inline std::optional<T> get_env_as(std::string const& key) | ||
{ | ||
if (auto e = get_env(key)) | ||
return from_string<T>(*e); | ||
return std::nullopt; | ||
} | ||
Comment on lines
+261
to
+267
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential conversion errors in The template<typename T>
NO_DISCARD inline std::optional<T> get_env_as(std::string const& key)
{
if (auto e = get_env(key))
{
try {
return from_string<T>(*e);
} catch (const std::exception& ex) {
std::cerr << "Error converting environment variable " << key << ": " << ex.what() << std::endl;
}
}
return std::nullopt;
} |
||
|
||
|
||
template<typename T> | ||
NO_DISCARD inline T get_env_as(std::string const& key, T const& t) | ||
{ | ||
if (auto e = get_env(key)) | ||
return from_string<T>(*e); | ||
return t; | ||
} | ||
Comment on lines
+270
to
+276
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential conversion errors in The template<typename T>
NO_DISCARD inline T get_env_as(std::string const& key, T const& t)
{
if (auto e = get_env(key))
{
try {
return from_string<T>(*e);
} catch (const std::exception& ex) {
std::cerr << "Error converting environment variable " << key << ": " << ex.what() << std::endl;
}
}
return t;
} |
||
|
||
|
||
|
||
} // namespace core | ||
} // namespace PHARE | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
cmake_minimum_required (VERSION 3.20.1) | ||
|
||
project(test-phare-env) | ||
|
||
set(SOURCES test_env.cpp) | ||
|
||
add_executable(${PROJECT_NAME} ${SOURCES}) | ||
|
||
target_include_directories(${PROJECT_NAME} PRIVATE | ||
${GTEST_INCLUDE_DIRS} | ||
) | ||
|
||
target_link_directories(${PROJECT_NAME} PUBLIC ${MPI_LIBRARY_PATH}) | ||
|
||
target_link_libraries(${PROJECT_NAME} PRIVATE | ||
phare_core | ||
MPI::MPI_C | ||
${GTEST_LIBS} | ||
) | ||
|
||
add_phare_test(${PROJECT_NAME} ${CMAKE_CURRENT_BINARY_DIR}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure proper error handling in
get
method.The
get
method retrieves environment variables but does not handle potential errors fromcore::get_env
. Consider adding error handling or logging to capture any issues that may arise.