{"id":40224625,"url":"https://github.com/lewoudar/configuror","last_synced_at":"2026-01-19T22:30:49.162Z","repository":{"id":34881113,"uuid":"184556639","full_name":"lewoudar/configuror","owner":"lewoudar","description":"Project configuration toolkit","archived":false,"fork":false,"pushed_at":"2024-07-15T19:36:27.000Z","size":516,"stargazers_count":3,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-22T04:30:38.556Z","etag":null,"topics":["configuration","dotenv","ini","json","python3","toml","yaml"],"latest_commit_sha":null,"homepage":"https://configuror.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lewoudar.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-05-02T09:47:13.000Z","updated_at":"2023-12-06T15:20:28.000Z","dependencies_parsed_at":"2024-04-14T22:36:33.247Z","dependency_job_id":null,"html_url":"https://github.com/lewoudar/configuror","commit_stats":{"total_commits":73,"total_committers":3,"mean_commits":"24.333333333333332","dds":0.06849315068493156,"last_synced_commit":"cbfb5854a8ef5c38a1a3ae7f958bbdcfa3bf1560"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/lewoudar/configuror","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewoudar%2Fconfiguror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewoudar%2Fconfiguror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewoudar%2Fconfiguror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewoudar%2Fconfiguror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lewoudar","download_url":"https://codeload.github.com/lewoudar/configuror/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lewoudar%2Fconfiguror/sbom","scorecard":{"id":586475,"data":{"date":"2025-08-11","repo":{"name":"github.com/lewoudar/configuror","commit":"d70d1ed050a8a95f8ff599ef14b1cf9d6035bb97"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/lewoudar/configuror/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/lewoudar/configuror/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/lewoudar/configuror/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/lewoudar/configuror/publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/lewoudar/configuror/publish.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/ci.yml:27","Warn: pipCommand not pinned by hash: .github/workflows/publish.yml:21","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"14 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-230 / GHSA-248v-346w-9cwc","Warn: Project is vulnerable to: GHSA-cpwx-vrp4-4pq7","Warn: Project is vulnerable to: GHSA-gmj6-6f8f-6699","Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj","Warn: Project is vulnerable to: GHSA-q2x7-8rv6-6q7h","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf","Warn: Project is vulnerable to: GHSA-48p4-8xcf-vxj5","Warn: Project is vulnerable to: GHSA-pq67-6m6q-mj2v","Warn: Project is vulnerable to: PYSEC-2024-187 / GHSA-rqc4-2hc7-8c8v","Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 9 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T20:38:42.405Z","repository_id":34881113,"created_at":"2025-08-20T20:38:42.405Z","updated_at":"2025-08-20T20:38:42.405Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28587238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T20:45:59.482Z","status":"ssl_error","status_checked_at":"2026-01-19T20:45:41.500Z","response_time":67,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["configuration","dotenv","ini","json","python3","toml","yaml"],"created_at":"2026-01-19T22:30:47.140Z","updated_at":"2026-01-19T22:30:49.138Z","avatar_url":"https://github.com/lewoudar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# configuror\n\n[![Pypi version](https://img.shields.io/pypi/v/configuror.svg)](https://pypi.org/project/configuror/)\n[![](https://github.com/lewoudar/configuror/workflows/CI/badge.svg)](https://github.com/lewoudar/configuror/actions)\n[![Coverage Status](https://codecov.io/gh/lewoudar/configuror/branch/master/graphs/badge.svg?branch=master)](https://codecov.io/gh/lewoudar/configuror)\n[![Documentation Status](https://readthedocs.org/projects/configuror/badge/?version=latest)](https://configuror.readthedocs.io/en/latest/?badge=latest)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/lewoudar/configuror)\n[![License Apache 2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0)\n[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://github.com/lewoudar/configuror)\n\nYour configuration management toolkit!\n\n## Why?\n\nWhile using [Flask](http://flask.pocoo.org/docs/1.0/), I realized that their Config class could be useful for any type\nof project. And the utility became more and more obvious to me when I looked at a project like\n[Ansible](https://docs.ansible.com/ansible/latest/index.html). If you look the\n[section](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)\nwhere they define variable precedence, you will notice that there may be several locations for the configuration files,\nand these configuration files can be written in different formats (json, yaml..).\n\nWhat if there was a simple tool that would aggregate information from different sources in the order you wanted? This\nis **why** the configuror project exists!\n\n## Installation\n\n```bash\npip install configuror\n```\n\nconfiguror works starting from **python 3.7**. It has a few dependencies:\n- [pyyaml](https://pypi.org/project/PyYAML/) \u003e= 5.1\n- [toml](https://pypi.org/project/toml/)\n\n## Documentation\n\nThe documentation is available at https://configuror.readthedocs.io/en/latest/.\n\n## Usage\n\nThe main class provided by configuror is `Config`. It is an extension of a regular dict object. There are two main ways\nto initialize it.\n\n### Using mapping files\n\n```python\nfrom configuror import Config\n\nmapping_files = {\n    'ini': ['foo.ini', 'bar.ini'],\n    'toml': ['foo.toml', 'bar.toml'],\n    'python': ['/path/to/python/file']\n}\nconfig = Config(mapping_files=mapping_files, ignore_file_absence=True)\n```\n\nYou can define a mapping of `file_type: \u003cfiles\u003e` where the `file_type` is the type of configuration file and `\u003cfiles\u003e`\nis the list of files from the lowest to the highest priority where values will be loaded.\n\nSince dictionaries are sorted starting from python3.6, the order of the keys is important as it will become the order of\nimportance of your files. For example in the example above, configuror will load values from files in the following order:\n- foo.ini\n- bar.ini\n- foo.toml\n- bar.toml\n- /path/to/python/file\n\nFor python files, only **uppercase** variables will be loaded.\n\nYou will notice the keyword argument `ignore_file_absence` in `Config` class initialization. If it is set to `True`, all\nfiles that does not exist will not raised `FileNotFoundError`. It comes in handy when you want to retrieve variables\nfrom files *that may or may not potentially exist*. By default this parameter is set to `False`.\n\nFile extension is not necessary when you use mapping files since the key is already telling which files we work with.\nThis is not the case with the second way to initialize `Config` class.\n\n### Using a list of files\n\n```python\nfrom configuror import Config\n\nfiles = [\n    'foo.yml',\n    'bar.toml',\n    'foobar.json',\n    '/path/to/python/file'\n    '.env'\n]\nconfig = Config(files=files)\n```\n\nIn this second form of initialization, you pass a list of files you want to retrieve values from the lowest to the\nhighest priority. File extension is **mandatory** here to help configuror to load the files properly.\n\nTo know file extensions supported by configuror, you can use the variable `EXTENSIONS`. it is a mapping\n`file_type: \u003cextensions\u003e` where `file_type` is a type of file supported like *yaml* and `extensions` is a list of\nrecognized extensions for this type of file, e.g: `[yml, yaml]`\n\nToday the file types supported are *toml*, *yaml*, *dotenv*, *ini*, *python* and *json*.\n\n### Other usages\n\nSince `Config` object is a dict-like object, you can pass arbitrary keyword arguments to initialize default values.\n\n```python\nfrom configuror import Config\n\nconfig = Config(FOO=2, BAR='a')\nprint(config)  # will print {'FOO': 2, 'BAR': 'a'}\n```\n\nYou can combine keyword arguments, mapping files and list of files at initialization. The order in which values will be\ninitialized is the following:\n- values from keyword arguments\n- values from mapping files\n- values from list of files\n\nYou can also add values from files after initialization. There are several practical methods for this:\n- `load_from_mapping_files(self, mapping_files: Dict[str, List[str]], ignore_file_absence: bool)`: It is in fact the\nmethod used under the hood when you initialized `Config` object by passing the parameter `mapping_files`.\n\n- `load_from_files(self, files: List[str], ignore_file_absence: bool)`: It is the method used under the hood when you\ninitialized `Config` objects by passing the parameter `files`.\n\n- `load_from_object(self, obj: Union[Object, str])`: `obj` can be an object or a path to a project module\n(with dotted notation). Only uppercase attributes of the corresponding object will be retrieved.\n\n- `load_from_python_file(self, filename: str, ignore_file_absence: bool)`: Loads values from an arbitrary python\nfile. It would be preferable if it were not a file related to your project (i.e a module). Only uppercase variables\nare considered.\n\n- `load_from_json(self, filename: str, ignore_file_absence: bool)`: Loads values from a json file.\n\n- `load_from_yaml(self, filename: str, ignore_file_absence: bool)`: Loads values from a yaml file.\n\n- `load_from_toml(self, filenames: Union[str, List[str]], ignore_file_absence: bool)`: Loads values from a toml file\nor a list of toml files.\n\n- `load_from_ini(self, filenames: Union[str, List], ignore_file_absence: bool, interpolation_method: str = 'basic')`:\nLoads values from an ini file or a list of ini files. There are two interpolation methods that can be used: **basic**\nor **extended** like explained in the\n[documentation](https://docs.python.org/3/library/configparser.html#interpolation-of-values).\n\n- `load_from_dotenv(self, filename: str, ignore_file_absence: bool)`: Loads values from a dotenv file.\n\nBonus: You also have the `update` method of a dict to add/update values.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewoudar%2Fconfiguror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flewoudar%2Fconfiguror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flewoudar%2Fconfiguror/lists"}