{"id":37065826,"url":"https://github.com/stephen1000/enpyronments","last_synced_at":"2026-01-14T07:43:16.576Z","repository":{"id":57426501,"uuid":"197610928","full_name":"stephen1000/enpyronments","owner":"stephen1000","description":"A python environment settings loader inspired by Django and Node.js","archived":false,"fork":false,"pushed_at":"2019-08-16T20:54:02.000Z","size":407,"stargazers_count":0,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-27T21:10:50.108Z","etag":null,"topics":["configuration","environments","python","settings"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stephen1000.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-18T15:16:00.000Z","updated_at":"2019-08-05T20:16:34.000Z","dependencies_parsed_at":"2022-09-11T06:17:49.559Z","dependency_job_id":null,"html_url":"https://github.com/stephen1000/enpyronments","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stephen1000/enpyronments","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen1000%2Fenpyronments","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen1000%2Fenpyronments/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen1000%2Fenpyronments/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen1000%2Fenpyronments/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephen1000","download_url":"https://codeload.github.com/stephen1000/enpyronments/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen1000%2Fenpyronments/sbom","scorecard":{"id":851434,"data":{"date":"2025-08-11","repo":{"name":"github.com/stephen1000/enpyronments","commit":"0848c55a2a1b132b3beba94265c103ba49385c8f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.2,"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":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"Code-Review","score":0,"reason":"Found 0/30 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":-1,"reason":"no workflows found","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":"Binary-Artifacts","score":0,"reason":"binaries present in source code","details":["Warn: binary detected: dist/enpyronments-0.1.0-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a0-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a1-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a2-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a3-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a4-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.1a5-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.2-py3-none-any.whl:1","Warn: binary detected: dist/enpyronments-0.1.3-py3-none-any.whl:1"],"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":"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":"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":"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":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":6,"reason":"4 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: PYSEC-2020-92 / GHSA-hj5v-574p-mj7c","Warn: Project is vulnerable to: PYSEC-2022-42969","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"}}]},"last_synced_at":"2025-08-23T22:39:39.996Z","repository_id":57426501,"created_at":"2025-08-23T22:39:39.996Z","updated_at":"2025-08-23T22:39:39.996Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28413476,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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","environments","python","settings"],"created_at":"2026-01-14T07:43:15.937Z","updated_at":"2026-01-14T07:43:16.564Z","avatar_url":"https://github.com/stephen1000.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# enpyronments\n\n**A Django/Node inspired environment settings library for the Python user on the go.**\n\n---\n\n# \u003cIn Development\u003e\n\nPlease note that this project is still very much in alpha, so a lot of things will be broken / untested until a more stable build exists.\n\n# Overview\n\nenpyronments is a fully configurable tool for abstracting away the hassle of configuration files.\n\nHere's some use cases:\n\n- Have a separate database address \u0026 connection string for dev, test, and prod, with your credentials either stored in an untracked \\*\\_local.py in settings.DATABASE_ADDRESS and settings.DATABASE_CONNECTION_STRING\n- Configure environment variables for both dev and prod servers at startup by calling settings.save_to_environ()\n- Have emails deferred or saved as drafts instead of sent while developing and testing based on settings.SEND_MAIL\n\nThe full documentation can be found at\nhttps://enpyronments.readthedocs.io/en/latest/contents.html\n\n# Requirements\n\n- Python (3.6, 3.7)\n\nAnd that's it! No external dependencies!\n\n# Installation\n\nInstall using `pip`\n\n    pip install enpyronments\n\n# Usage Explanation\n\nLet's say we're making an ultra-complex application that needs to print a message a certain number of times, depending on who / where our app is running. Let's say it looks something like this:\n\n```python\n# main.py\n\nfrom . import settings\n\ndef main():\n    for _ in range settings.LINES_TO_PRINT:\n        print(settings.MESSAGE)\n\n\nif __name__ == '__main__':\n    main()\n```\n\nAnd next to it, the configuration:\n\n```python\n# settings.py\n\nLINES_TO_PRINT = 10\nMESSAGE = 'test message please ignore'\n```\n\nSeems straightforward enough, right? We can just have our app import those settings from a .py file right next to it, and poof, problem solved!\n\nNow, let's say that we've deployed this code to our production machine, and it's running just great. Our customers are happy*ish*, but a few of them would happier if the message had a date attached to it.\n\nWe can instruct them to change their settings file like so:\n\n```python\n# settings.py\n\nimport datetime as dt\n\nLINES_TO_PRINT = 10\nMESSAGE =  f'{dt.date.today():%x}: test message please ignore'\n```\n\nOk, that's easy enough, but now we've got two different versions of our settings.py file. How do we choose which one should be in our repository?\n\nThat's where enpyronments comes in. We'll get started by creating a folder for all of our different settings to go in to. Where you place the folder is up to you, but next to the code, in the same repository is a good idea.\n\nSo our new setup looks like this:\n\n    src\\\n        main.py\n    configuration\\\n        env.py\n        env_local.py\n\nOur default settings would go into env.py:\n\n```python\n# configuration\\env.py\n\nLINES_TO_PRINT = 10\nMESSAGE = 'test message please ignore'\n```\n\nAnd our users would just have to modify the env_local.py file to change the settings they want to override:\n\n```python\n# configuration\\env_local.py\n\nimport datetime as dt\n\nMESSAGE =  f'{dt.date.today():%x}: test message please ignore'\n```\n\nOr, even better, you can import the default setting and change it for your local environment:\n\n```python\n# configuration\\env_local.py\n\nimport datetime as dt\n\nfrom . import env\n\nMESSAGE =  f'{dt.datetime.today():%x}: {env.MESSAGE}'\n```\n\nWe can load those into our app with enpyronments:\n\n```python\n# src\\main.py\n\nfrom enpyronments.loader import Loader\n\nloader = Loader('path/to/parent/dir')\nsettings = Loader.load_settings('configuration')\n\nfor _ in range(settings.LINES_TO_PRINT):\n    print(settings.MESSAGE)\n```\n\nThat's all fine and dandy, but maybe you want to pull a message from an external source using something like requests. That's pretty easily done:\n\n```python\n# configuration\\env.py\n\nimport requests\n\nresponse = requests.get('https://xkcd.com/info.0.json')\ndata = response.content\ncomic_title = data.get('title')\n\nif comic_title:\n    MESSAGE = f\"Today's xkcd is called '{comic_title}'\"\nelse:\n    MESSAGE = f\"Sorry, we couldn't load the title of today's xkcd :(\"\n```\n\nAnd lastly (or more likely beforehand), you'll probably want to make sure you don't track the localized settings in your repository, so add them to your .gitignore:\n\n```\n# .gitignore\n\nconfiguration\\*_local.py\n```\n\n# Example Application\n\nHere is a walkthrough of the provided sample setup for an app with two modes, \"dev\" and \"prod\":\n\n    sample_app\\\n        main.py\n        sample_settings\\\n            env_dev_local.py\n            env_dev.py\n            env_local.py\n            env_prod_local.py\n            env_prod.py\n            env.py\n\nYou'll notice there's 6 different settings files. Here's what each is doing:\n\n- env.py: Default application settings that you track in your repository. Could contain settings like APP_NAME, TARGET_URL, JSON_PAYLOAD, LOGGING_CONFIG, etc.\n\n- env_local.py: Primarily used to determine the local environment's MODE (i.e. if we're running in development, we'd have MODE=\"dev\"). Can be used for sensitive information in apps that don't need different modes, as well. These will override any settings found in env.py\n\n- env_dev.py: Settings for when we're in development mode. We can do things like set SEND_MAIL=False, to indicate that we won't be sending out emails while we're working on the app. These override any settings found in env.py.\n\n- env_dev_local.py: Settings for our local development machine. Things like database connection strings or account credentials can be set here (make sure you don't track these in source control!!!!). If you want to use those settings, but don't want them stored in a file, you can use os.environ to pull them from the operating system's environment variables.\n\n- env_prod.py: Same as env_dev.py, but for production.\n\n- env_prod_local.py: Same as env_dev_local.py, but for production.\n\nTake a minute and check out the contents of those files in /sample_app.\n\nIn development, our settings will look like:\n\n    {\n        \"APP_NAME\": \"enpyronments\",\n        \"LINES_TO_PRINT\": 5,\n        \"MODE\": \"dev\",\n        \"DEBUG\": true,\n        \"DEBUG_EMAIL_ADDRESS\": \"foo@bar.baz\",\n        \"WELCOME_MESSAGE\": \"ayyy whattup\",\n        \"SECRET_KEY\": \"hey man dont steal my secret key\",\n        \"EMAIL_SERVER_LOGIN\": \"my_username\",\n        \"EMAIL_SERVER_PASSWORD\": \"my_password\",\n        \"SECRET_NUMBER\": 3\n    }\n\nIn production, we'd have:\n\n    {\n        \"APP_NAME\": \"enpyronments\",\n        \"LINES_TO_PRINT\": 20,\n        \"MODE\": \"prod\",\n        \"WELCOME_MESSAGE\": \"Welcome to Jurrasic Park!\",\n        \"SECRET_KEY\": \"SUPREMELY SECRET- DO NOT SHARE!!!\",\n        \"EMAIL_SERVER_LOGIN\": \"resource_account_user\",\n        \"EMAIL_SERVER_PASSWORD\": \"resource_account_password\"\n    }\n\nAnd we can access those in the code in just a few lines:\n\n```python\n# main.py\n\nfrom enpyronments.loader import Loader\n\napp_dir = \"sample_app\"\nsettings_dir = \"sample_settings\"\nroot = os.path.join(os.path.dirname(__file__), app_dir)\n\nloader = Loader(root)\nsettings = loader.load_settings(settings_dir)\n```\n\n# Further reading\n\nThe full documentation is available at\nhttps://enpyronments.readthedocs.io/en/latest/contents.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephen1000%2Fenpyronments","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephen1000%2Fenpyronments","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephen1000%2Fenpyronments/lists"}