<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
 * @author <NAME>
 */
import java.io.{ OutputStream, PrintStream }
import java.nio.file.{ Files, Path }

import scala.annotation.tailrec
import scala.reflect.ClassTag

import com.typesafe.config.{ Config => TypesafeConfig, _ }
import pureconfig.ConvertHelpers._
import pureconfig.backend.ConfigFactoryWrapper._
import pureconfig.backend.PathUtil
import pureconfig.backend.PathUtil._
import pureconfig.error._

package object pureconfig {

  // retrieves a value from a namespace, returning a failure if:
  //   - one of the parent keys doesn't exist or isn't an object;
  //   - `allowNullLeaf` is false and the leaf key doesn't exist.
  private[this] def getValue(conf: TypesafeConfig, namespace: String, allowNullLeaf: Boolean): Either[ConfigReaderFailures, ConfigValue] = {
    @tailrec def getValue(cv: ConfigValue, path: List[String], curr: List[String]): Either[ConfigReaderFailures, ConfigValue] = {
      (cv, path) match {
        case (_, Nil) => Right(cv)

        case (co: ConfigObject, key :: remaining) =>
          co.get(key) match {
            case null if remaining.nonEmpty || !allowNullLeaf =>
              fail(KeyNotFound(joinPath((key :: curr).reverse), ConfigValueLocation(cv.origin()), Set.empty))
            case childCv =>
              getValue(childCv, remaining, key :: curr)
          }

        case _ => fail(WrongType(
          cv.valueType, Set(ConfigValueType.OBJECT), ConfigValueLocation(cv.origin()), joinPath(curr.reverse)))
      }
    }

    // we're not expecting any exception here, this `try` is just for extra safety
    try getValue(conf.root(), splitPath(namespace), Nil) catch {
      case ex: ConfigException => fail(ThrowableFailure(ex, ConfigValueLocation(ex.origin()), ""))
    }
  }

  // loads a value from a config in a given namespace. All `loadConfig` methods _must_ use this method to get correct
  // namespace handling, both in the values to load and in the error messages.
  private[this] def loadValue[A](conf: TypesafeConfig, namespace: String)(implicit reader: Derivation[ConfigReader[A]]): Either[ConfigReaderFailures, A] = {
    getValue(conf, namespace, reader.value.isInstanceOf[AllowMissingKey]).right.flatMap { cv =>
      val cur = ConfigCursor(cv, PathUtil.splitPath(namespace))
      reader.value.from(cur)
    }
  }

  /**
   * Load a configuration of type `Config` from the standard configuration files
   *
   * @return A `Success` with the configuration if it is possible to create an instance of type
   *         `Config` from the configuration files, else a `Failure` with details on why it
   *         isn't possible
   */
  def loadConfig[Config](implicit reader: Derivation[ConfigReader[Config]]): Either[ConfigReaderFailures, Config] =
    loadConfig("")

  /**
   * Load a configuration of type `Config` from the standard configuration files
   *
   * @param namespace the base namespace from which the configuration should be load
   * @return A `Success` with the configuration if it is possible to create an instance of type
   *         `Config` from the configuration files, else a `Failure` with details on why it
   *         isn't possible
   */
  def loadConfig[Config](namespace: String)(implicit reader: Derivation[ConfigReader[Config]]): Either[ConfigReaderFailures, Config] = {<commit_msg>Simplify loadConfig with namespace using the cursor API<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
 * @author <NAME>
 */
import java.io.{ OutputStream, PrintStream }
import java.nio.file.{ Files, Path }

import scala.reflect.ClassTag

import com.typesafe.config.{ Config => TypesafeConfig, _ }
import pureconfig.ConvertHelpers._
import pureconfig.backend.ConfigFactoryWrapper._
import pureconfig.backend.PathUtil._
import pureconfig.error._

package object pureconfig {

  // retrieves a value from a namespace, returning a failure if:
  //   - one of the parent keys doesn't exist or isn't an object;
  //   - `allowNullLeaf` is false and the leaf key doesn't exist.
  private[this] def getValue(conf: TypesafeConfig, namespace: String, allowNullLeaf: Boolean): Either[ConfigReaderFailures, ConfigCursor] = {
    def getValue(cur: ConfigCursor, path: List[String]): Either[ConfigReaderFailures, ConfigCursor] = path match {
      case Nil => Right(cur)
      case key :: remaining => for {
        objCur <- cur.asObjectCursor
        keyCur <- if (remaining.nonEmpty || !allowNullLeaf) objCur.atKey(key) else Right(objCur.atKeyOrUndefined(key))
        finalCur <- getValue(keyCur, remaining)
      } yield finalCur
    }

    // we're not expecting any exception here, this `try` is just for extra safety
    try getValue(ConfigCursor(conf.root(), Nil), splitPath(namespace)) catch {
      case ex: ConfigException => fail(ThrowableFailure(ex, ConfigValueLocation(ex.origin()), ""))
    }
  }

  // loads a value from a config in a given namespace. All `loadConfig` methods _must_ use this method to get correct
  // namespace handling, both in the values to load and in the error messages.
  private[this] def loadValue[A](conf: TypesafeConfig, namespace: String)(implicit reader: Derivation[ConfigReader[A]]): Either[ConfigReaderFailures, A] = {
    getValue(conf, namespace, reader.value.isInstanceOf[AllowMissingKey]).right.flatMap(reader.value.from)
  }

  /**
   * Load a configuration of type `Config` from the standard configuration files
   *
   * @return A `Success` with the configuration if it is possible to create an instance of type
   *         `Config` from the configuration files, else a `Failure` with details on why it
   *         isn't possible
   */
  def loadConfig[Config](implicit reader: Derivation[ConfigReader[Config]]): Either[ConfigReaderFailures, Config] =
    loadConfig("")

  /**
   * Load a configuration of type `Config` from the standard configuration files
   *
   * @param namespace the base namespace from which the configuration should be load
   * @return A `Success` with the configuration if it is possible to create an instance of type
   *         `Config` from the configuration files, else a `Failure` with details on why it
   *         isn't possible
   */
  def loadConfig[Config](namespace: String)(implicit reader: Derivation[ConfigReader[Config]]): Either[ConfigReaderFailures, Config] = {
{'fraction_non_alphanumeric': 0.10159542444310657, 'fraction_numerical': 0.0012040939193257074, 'mean_word_length': 3.736279401282965, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3303507', 'n_tokens_mistral': 1855, 'n_tokens_neox': 1803, 'n_words': 653}