{"id":13625743,"url":"https://github.com/operatorequals/httpimport","last_synced_at":"2026-01-16T12:29:43.214Z","repository":{"id":44388965,"uuid":"101080467","full_name":"operatorequals/httpimport","owner":"operatorequals","description":"Module for remote in-memory Python package/module loading through HTTP/S","archived":false,"fork":false,"pushed_at":"2025-03-05T11:14:59.000Z","size":207,"stargazers_count":327,"open_issues_count":5,"forks_count":42,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-09-01T07:42:50.713Z","etag":null,"topics":["finder","github","http","importer","in-memory","loader","modules","packages","python","remote"],"latest_commit_sha":null,"homepage":"","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/operatorequals.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,"governance":null}},"created_at":"2017-08-22T15:49:00.000Z","updated_at":"2025-08-12T15:39:58.000Z","dependencies_parsed_at":"2023-02-16T01:45:35.616Z","dependency_job_id":"19732173-c6df-4451-bdca-1fe9c9e530b0","html_url":"https://github.com/operatorequals/httpimport","commit_stats":{"total_commits":174,"total_committers":7,"mean_commits":"24.857142857142858","dds":"0.16666666666666663","last_synced_commit":"4995508d146bc68f1c4fcc55287e5273fe2b8b12"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/operatorequals/httpimport","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fhttpimport","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fhttpimport/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fhttpimport/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fhttpimport/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/operatorequals","download_url":"https://codeload.github.com/operatorequals/httpimport/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/operatorequals%2Fhttpimport/sbom","scorecard":{"id":710909,"data":{"date":"2025-08-11","repo":{"name":"github.com/operatorequals/httpimport","commit":"9ce1a85cedf6deff97a51c44912f8f37c5b7cc3f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Code-Review","score":1,"reason":"Found 3/26 approved changesets -- score normalized to 1","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/python-package.yml:1","Warn: no topLevel permission defined: .github/workflows/python-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":"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":"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":"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":"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":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/operatorequals/httpimport/python-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/operatorequals/httpimport/python-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/operatorequals/httpimport/python-publish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-publish.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/operatorequals/httpimport/python-publish.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/python-package.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:31","Warn: pipCommand not pinned by hash: .github/workflows/python-publish.yml:32","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   5 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":"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":"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":"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/python-publish.yml:19"],"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":"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 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-22T08:11:23.880Z","repository_id":44388965,"created_at":"2025-08-22T08:11:23.880Z","updated_at":"2025-08-22T08:11:23.880Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478656,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"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":["finder","github","http","importer","in-memory","loader","modules","packages","python","remote"],"created_at":"2024-08-01T21:02:00.889Z","updated_at":"2026-01-16T12:29:43.191Z","avatar_url":"https://github.com/operatorequals.png","language":"Python","readme":"# httpimport\n## *Python's missing feature!*\n##### [The feature has been suggested in Python Mailing List](https://lwn.net/Articles/732194/)\n\n_Remote_, _in-memory_ Python _package/module_ `import`ing **through HTTP/S**\n\n[![Downloads](https://img.shields.io/pypi/dm/httpimport)](https://pypi.org/project/httpimport/)\n\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/httpimport)\n[![PyPI version](https://badge.fury.io/py/httpimport.svg)](https://pypi.python.org/pypi/httpimport)\n[![Python package](https://github.com/operatorequals/httpimport/actions/workflows/python-package.yml/badge.svg?branch=master)](https://github.com/operatorequals/httpimport/actions/workflows/python-package.yml)\n\n![CPython 3](https://img.shields.io/badge/Works%20on-CPython%203-brightgreen)\n![Pypy 3](https://img.shields.io/badge/Works%20on-Pypy%203-yellowgreen)\n\nA feature that _Python_ **misses** and has become popular in other languages is the **remote loading of packages/modules**.\n\n`httpimport` lets Python packages and modules to be *installed* and *imported* directly in Python interpreter's process memory, through **remote `URIs`**, and *more*...\n\n#### **Python2 support has been discontinued**. Last version that supports Python2 is [`1.1.0`](https://pypi.org/project/httpimport/1.1.0/).\n\n## Basic Usage\n\n### Load package/module accessible through any HTTP/S location\n```python\nwith httpimport.remote_repo('http://my-codes.example.com/python_packages'):\n  import package1\n```\n\n### Load a module from PyPI:\n```python\nwith httpimport.pypi_repo():\n  import distlib # https://pypi.org/project/distlib/\n\nprint(distlib.__version__)\n# '0.3.6' \u003c-- currently latest (https://github.com/pypa/distlib/blob/0.3.6/distlib/__init__.py#L9)\n```\n\n### Load directly from a GitHub/BitBucket/GitLab repo\n```python\nwith httpimport.github_repo('operatorequals', 'httpimport', ref='master'):\n  import httpimport as httpimport_upstream\n  # Also works with 'bitbucket_repo' and 'gitlab_repo'\n```\n\n### Load a Python module from a Github Gist (using [this gist](https://gist.github.com/operatorequals/ee5049677e7bbc97af2941d1d3f04ace)):\n```python\nurl = \"https://gist.githubusercontent.com/operatorequals/ee5049677e7bbc97af2941d1d3f04ace/raw/e55fa867d3fb350f70b2897bb415f410027dd7e4\"\n\nwith httpimport.remote_repo(url):\n  import hello\n\nhello.hello()\n# Hello world\n```\n\n### Load a package/module directly to a variable\n```python\n# From HTTP/S URL\nhttp_module = httpimport.load('package1', 'https://my-codes.example.com/python_packages')\nprint(http_module)\n\u003cmodule 'package1' from 'https://my-codes.example.com/python_packages/package1/__init__.py'\u003e\n\n# From PyPI\npypi_module = httpimport.load('distlib', importer_class=httpimport.PyPIImporter)\nprint(pypi_module)\n\u003cmodule 'distlib' from 'https://files.pythonhosted.org/packages/76/cb/6bbd2b10170ed991cf64e8c8b85e01f2fb38f95d1bc77617569e0b0b26ac/distlib-0.3.6-py2.py3-none-any.whl#distlib/__init__.py'\u003e\n```\n\n### Load Python packages from archives served through HTTP/S\n*No file is touching the disk in the process*\n```python\n# with httpimport.remote_repo('https://example.com/packages.tar'):\n# with httpimport.remote_repo('https://example.com/packages.tar.bz2'):\n# with httpimport.remote_repo('https://example.com/packages.tar.gz'):\n# with httpimport.remote_repo('https://example.com/packages.tar.xz'):\nwith httpimport.remote_repo('https://example.com/packages.zip'):\n  import test_package\n```\n\n## Serving a package through HTTP/S\nAny package can be served for `httpimport` using a simple HTTP/S Server:\n```bash\necho 'print(\"Hello httpimport!\")' \u003e module.py\npython -m http.server\nServing HTTP on 0.0.0.0 port 8000 ...\n\n```\n\n```python\n\u003e\u003e\u003e import httpimport\n\u003e\u003e\u003e with httpimport.remote_repo(\"http://127.0.0.1:8000\"):\n...   import module\n...\nHello httpimport!\n```\n\n## Profiles\nAfter `v1.0.0` it is possible to set HTTP Authentication, Custom Headers, Proxies and several other things using *URL* and *Named Profiles*!\n\n### URL Profiles\nURL Profiles are INI configurations, setting specific per-URL options, as below:\n\n```ini\n[http://127.0.0.1:8000]\nallow-plaintext: yes ; also 'true' and '1' evaluate to True\n\n[https://example.com]\nproxy-url: https://127.0.0.1:8080 ; values must not be in quotes (')\n\n```\n\nNow, requests to `http://127.0.0.1:8000` will be allowed (HTTP URLs do not work by default) and requests to `https://example.com` will be sent to an HTTP Proxy.\n\n```python\nwith httpimport.remote_repo(\"https://example.com\"): # URL matches the URL profile\n  import module_accessed_through_proxy\n```\n### Named Profiles\nNamed Profiles are like URL profiles but do not specify a URL and need to be explicitly used:\n\n```ini\n[github]\nheaders:\n  Authorization: token \u003cGithub-Token\u003e\n```\n\nAnd the above can be used as follows:\n\n```python\nwith httpimport.github_repo('operatorequals','httpimport-private-test', profile='github'):\n  import secret_module\n```\n\n##### Github Tokens look like `github_pat_\u003cgibberish\u003e` and can be issued here: https://github.com/settings/tokens/new\n\n### Profiles for PyPI\nWhen importing from PyPI extra options can be used, as described in the profile below:\n\n```ini\n[pypi]\n\n# The location of a 'requirements.txt' file\n# to use for PyPI project versions\nrequirements-file: requirements-dev.txt\n\n# Inline 'requirements.txt' syntax appended\nrequirements:\n  distlib==0.3.5\n  sampleproject==3.0.0\n\n# Only version pinning notation is supported ('==')\n# with 'requirements' and 'requirements-file' options\n\n# A map that contains 'module': 'PyPI project' tuples\n# i.e: 'import sample' --\u003e search 'sample' module at 'sampleproject' PyPI Project:\n# https://pypi.org/project/sampleproject/\nproject-names:\n  sample: sampleproject\n```\n\nThe PyPI Profiles can be used exactly like all *Named Profiles*:\n\n```python\nwith httpimport.pypi_repo(profile='pypi'):\n  import distlib\n  import sample\ndistlib.__version__\n# '0.3.5' \u003c-- pinned in the profile 'requirements' option\nsample.__url__\n# 'https://files.pythonhosted.org/packages/ec/a8/5ec62d18adde798d33a170e7f72930357aa69a60839194c93eb0fb05e59c/sampleproject-3.0.0-py3-none-any.whl#sample/__init__.py' \u003c-- loaded from 'sampleproject'\n```\n\nAdditionally, all other options cascade to PyPI profiles, such as HTTPS Proxy (HTTP proxies won't work, as PyPI is hosted with HTTPS), `headers`, etc.\n\n##### NOTE: The values in Profiles MUST NOT be quoted (`'`,`\"`)\n\n### Profile Creation\nProfiles can be provided as INI strings to the `set_profile` function and used in all `httpimport` functions:\n```python\nhttpimport.set_profile(\"\"\"\n[profile1]\n\nproxy-url: https://my-proxy.example.com\nheaders:\n  Authorization: Basic ...\n  X-Hello-From: httpimport\n  X-Some-Other: HTTP header\n\"\"\")\nwith httpimport.remote_repo(\"https://code.example.com\", profile='profile1'):\n  import module_accessed_through_proxy\n```\n\n#### Advanced\nProfiles are INI configuration strings parsed using Python [`configparser`](https://docs.python.org/3/library/configparser.html) module.\n\nThe `ConfigParser` object for `httpimport` is the global variable `httpimport.CONFIG` and can be used freely:\n\n```python\nimport httpimport\nhttpimport.CONFIG.read('github.ini') # Read profiles from a file\n\nwith httpimport.github_repo('operatorequals','httpimport-private-test', profile='github'):\n  import secret_module\n```\n\n## Default Profiles\nThe `httpimport` module automatically loads Profiles found in `$HOME/.httpimport.ini` and under the `$HOME/.httpimport/` directory. Profiles under `$HOME/.httpimport/` override ones found in `$HOME/.httpimport.ini`.\n\n### Profile Options:\n#### Supported\nHTTP options\n* `zip-password` - `v1.0.0`\n* `proxy-url` - `v1.0.0`\n* `headers` - `v1.0.0`\n* `allow-plaintext` - `v1.0.0`\n* `ca-verify` - `v1.3.0`\n* `ca-file` - `v1.3.0`\n\nPyPI-only options\n* `project-names` - `v1.2.0`\n* `requirements` - `v1.2.0`\n* `requirements-file` - `v1.2.0`\n\n#### Not yet (subject to change)\n* `allow-compiled`\n\n* `auth`\n* `auth-type`\n\n* `tls-cert`\n* `tls-key`\n* `tls-passphrase`\n\n## Debugging...\n```python\nimport httpimport\nimport logging\n\nlogging.getLogger('httpimport').setLevel(logging.DEBUG)\n```\n\n## Beware: **Huge Security Implications!**\n_Using the `httpimport` with plain **HTTP URLs** is highly discouraged_\n  \nAs HTTP traffic can be read and changed from all intermediate hosts (_unlike HTTPS_), it is possible for a remote adversary to alter the HTTP responses consumed by `httpimport` and add arbitrary _Python_ code to the downloaded _packages/modules_. This directly results in arbitrary _Remote Code Execution_ on your current user's context of your host!\n\nIn other words, using plain HTTP through the Internet can compromise your host *without a way to notice it*.\n\n##### You have been warned! Use only **HTTPS URLs** with `httpimport`!\n\n## Contributors\n* [ldsink](https://github.com/ldsink) - The `RELOAD` flag and Bug Fixes\n* [lavvy](https://github.com/lavvy) - the `load()` function\n* [superloach](https://github.com/superloach) - Deprecation of `imp` module in Python3 in favour of `importlib`\n* [yanliakos](https://github.com/yanliakos) - Bug Fix\n* [rkbennett](https://github.com/rkbennett) - Relative Imports fix, Proxy support\n\n## Donations\nIn case my work helped you, you can always buy me a beer or a liter of gas [through the Internet](https://www.buymeacoffee.com/operatorequals) or in case you meet me personally.\n\nIn the second case we can talk about any video of [Internet Historian](https://www.youtube.com/@InternetHistorian) or [Ordinary Things](https://www.youtube.com/@OrdinaryThings), while listening to a [Lofi Girl Playlist](https://www.youtube.com/watch?v=jfKfPfyJRdk), like the citizens of the Internet that we are.\n\n[![donation](https://cdn-images-1.medium.com/max/738/1*G95uyokAH4JC5Ppvx4LmoQ@2x.png)](https://www.buymeacoffee.com/operatorequals)\n","funding_links":["https://www.buymeacoffee.com/operatorequals"],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatorequals%2Fhttpimport","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foperatorequals%2Fhttpimport","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foperatorequals%2Fhttpimport/lists"}