ghostpkg 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ghostpkg/data.py ADDED
@@ -0,0 +1,399 @@
1
+ """Popular package names, used only for typo-distance comparison.
2
+
3
+ Generated from the top-pypi-packages dataset (hugovk.github.io).
4
+ Regenerate with: python tools/refresh_data.py
5
+ """
6
+
7
+ # 2000 most-downloaded PyPI projects
8
+ TOP_PYPI = frozenset([
9
+ 'a2a-sdk', 'a2wsgi', 'absl-py', 'accelerate', 'adal', 'addict', 'adlfs', 'aenum', 'affine',
10
+ 'ag-ui-protocol', 'agate', 'agent-client-protocol', 'aio-pika', 'aioboto3', 'aiobotocore',
11
+ 'aiocache', 'aiodns', 'aiofile', 'aiofiles', 'aiohappyeyeballs', 'aiohttp', 'aiohttp-cors',
12
+ 'aiohttp-retry', 'aioitertools', 'aiokafka', 'aiolimiter', 'aiomysql', 'aioquic',
13
+ 'aioresponses', 'aiormq', 'aiosignal', 'aiosmtplib', 'aiosqlite', 'alabaster', 'alembic',
14
+ 'alibabacloud-credentials', 'alibabacloud-tea-openapi', 'aliyun-semantic-conventions',
15
+ 'aliyun-trace', 'allure-pytest', 'allure-python-commons', 'altair', 'altgraph',
16
+ 'amazon-ion', 'amplitude-analytics', 'amqp', 'aniso8601', 'annotated-doc',
17
+ 'annotated-types', 'ansible', 'ansible-compat', 'ansible-core', 'ansicolors', 'anthropic',
18
+ 'antlr4-python3-runtime', 'anyio', 'anytree', 'apache-airflow', 'apache-airflow-core',
19
+ 'apache-airflow-providers-amazon', 'apache-airflow-providers-cncf-kubernetes',
20
+ 'apache-airflow-providers-common-compat', 'apache-airflow-providers-common-io',
21
+ 'apache-airflow-providers-common-sql', 'apache-airflow-providers-databricks',
22
+ 'apache-airflow-providers-fab', 'apache-airflow-providers-ftp',
23
+ 'apache-airflow-providers-google', 'apache-airflow-providers-http',
24
+ 'apache-airflow-providers-imap', 'apache-airflow-providers-mysql',
25
+ 'apache-airflow-providers-slack', 'apache-airflow-providers-smtp',
26
+ 'apache-airflow-providers-snowflake', 'apache-airflow-providers-sqlite',
27
+ 'apache-airflow-providers-ssh', 'apache-airflow-task-sdk', 'apache-tvm-ffi', 'apispec',
28
+ 'appdirs', 'applicationinsights', 'appnope', 'apprise', 'apscheduler', 'arabic-reshaper',
29
+ 'argcomplete', 'argon2-cffi', 'argon2-cffi-bindings', 'argparse', 'arro3-core', 'arrow',
30
+ 'arxiv', 'asgi-lifespan', 'asgiref', 'asn1crypto', 'ast-serialize', 'asteval', 'astor',
31
+ 'astroid', 'astronomer-cosmos', 'asttokens', 'astunparse', 'async-lru', 'async-timeout',
32
+ 'asyncer', 'asyncio', 'asyncpg', 'asyncssh', 'asynctest', 'atlassian-python-api',
33
+ 'atpublic', 'attrs', 'audioop-lts', 'audioread', 'auth0-python', 'authlib', 'autobahn',
34
+ 'autoflake', 'automat', 'autopep8', 'av', 'avro', 'avro-python3', 'aws-cdk-asset-awscli-v1',
35
+ 'aws-cdk-asset-node-proxy-agent-v6', 'aws-cdk-cloud-assembly-schema', 'aws-cdk-lib',
36
+ 'aws-lambda-powertools', 'aws-msk-iam-sasl-signer-python', 'aws-requests-auth',
37
+ 'aws-sam-translator', 'aws-xray-sdk', 'awscli', 'awscrt', 'awswrangler', 'azure-ai-agents',
38
+ 'azure-ai-documentintelligence', 'azure-ai-projects', 'azure-appconfiguration',
39
+ 'azure-batch', 'azure-cli', 'azure-cli-core', 'azure-common', 'azure-core',
40
+ 'azure-core-tracing-opentelemetry', 'azure-cosmos', 'azure-data-tables',
41
+ 'azure-datalake-store', 'azure-eventgrid', 'azure-eventhub', 'azure-functions',
42
+ 'azure-identity', 'azure-keyvault', 'azure-keyvault-certificates', 'azure-keyvault-keys',
43
+ 'azure-keyvault-secrets', 'azure-kusto-data', 'azure-kusto-ingest', 'azure-mgmt-advisor',
44
+ 'azure-mgmt-applicationinsights', 'azure-mgmt-authorization', 'azure-mgmt-batch',
45
+ 'azure-mgmt-batchai', 'azure-mgmt-billing', 'azure-mgmt-cdn',
46
+ 'azure-mgmt-cognitiveservices', 'azure-mgmt-compute', 'azure-mgmt-containerinstance',
47
+ 'azure-mgmt-containerregistry', 'azure-mgmt-containerservice', 'azure-mgmt-core',
48
+ 'azure-mgmt-cosmosdb', 'azure-mgmt-datafactory', 'azure-mgmt-datalake-nspkg',
49
+ 'azure-mgmt-datalake-store', 'azure-mgmt-datamigration', 'azure-mgmt-eventgrid',
50
+ 'azure-mgmt-eventhub', 'azure-mgmt-iotcentral', 'azure-mgmt-iothub',
51
+ 'azure-mgmt-iothubprovisioningservices', 'azure-mgmt-keyvault', 'azure-mgmt-loganalytics',
52
+ 'azure-mgmt-managementgroups', 'azure-mgmt-maps', 'azure-mgmt-marketplaceordering',
53
+ 'azure-mgmt-media', 'azure-mgmt-monitor', 'azure-mgmt-msi', 'azure-mgmt-network',
54
+ 'azure-mgmt-nspkg', 'azure-mgmt-policyinsights', 'azure-mgmt-rdbms',
55
+ 'azure-mgmt-recoveryservices', 'azure-mgmt-recoveryservicesbackup', 'azure-mgmt-redis',
56
+ 'azure-mgmt-resource', 'azure-mgmt-search', 'azure-mgmt-servicebus',
57
+ 'azure-mgmt-servicefabric', 'azure-mgmt-signalr', 'azure-mgmt-sql', 'azure-mgmt-storage',
58
+ 'azure-mgmt-trafficmanager', 'azure-mgmt-web', 'azure-monitor-opentelemetry',
59
+ 'azure-monitor-opentelemetry-exporter', 'azure-monitor-query', 'azure-nspkg',
60
+ 'azure-search-documents', 'azure-servicebus', 'azure-storage-blob', 'azure-storage-common',
61
+ 'azure-storage-file-datalake', 'azure-storage-file-share', 'azure-storage-queue',
62
+ 'azure-synapse-artifacts', 'azure-synapse-spark', 'babel', 'backcall', 'backoff',
63
+ 'backports-asyncio-runner', 'backports-strenum', 'backports-tarfile', 'backports-zoneinfo',
64
+ 'backports-zstd', 'backrefs', 'bandit', 'banks', 'basedpyright', 'bashlex',
65
+ 'bazel-runfiles', 'bcrypt', 'beartype', 'beautifulsoup4', 'bedrock-agentcore', 'behave',
66
+ 'bidict', 'billiard', 'binaryornot', 'biopython', 'bitarray', 'bitsandbytes', 'black',
67
+ 'blake3', 'bleach', 'blessed', 'blinker', 'blis', 'blobfile', 'bluetooth-data-tools',
68
+ 'bokeh', 'boltons', 'boolean-py', 'boostedblob', 'boto', 'boto3', 'boto3-stubs', 'botocore',
69
+ 'botocore-stubs', 'bottle', 'bottleneck', 'bracex', 'braintrust', 'brotli',
70
+ 'browser-harness', 'browser-use', 'browser-use-sdk', 'bs4', 'bubus', 'build',
71
+ 'burner-redis', 'bytecode', 'c7n-org', 'cachebox', 'cachecontrol', 'cached-property',
72
+ 'cachelib', 'cachetools', 'cadwyn', 'caio', 'cairocffi', 'cairosvg', 'cassandra-driver',
73
+ 'catalogue', 'catboost', 'cattrs', 'cbor2', 'cchardet', 'cdp-use', 'cel-python', 'celery',
74
+ 'celery-redbeat', 'cerberus', 'certifi', 'cffi', 'cfgv', 'cfn-lint', 'channels', 'chardet',
75
+ 'charset-normalizer', 'checkdigit', 'checkov', 'chevron', 'chromadb', 'circuitbreaker',
76
+ 'ciso8601', 'ckzg', 'clarabel', 'claude-agent-sdk', 'cleo', 'click', 'click-default-group',
77
+ 'click-didyoumean', 'click-option-group', 'click-plugins', 'click-repl',
78
+ 'clickhouse-connect', 'clickhouse-driver', 'cligj', 'cloud-sql-python-connector',
79
+ 'cloudevents', 'cloudflare', 'cloudpathlib', 'cloudpickle', 'cmake', 'cmdstanpy', 'cobble',
80
+ 'codeowners', 'codespell', 'cohere', 'colorama', 'colorclass', 'coloredlogs', 'colorful',
81
+ 'colorlog', 'comm', 'compressed-rtf', 'compressed-tensors', 'confection', 'configargparse',
82
+ 'configobj', 'configparser', 'confluent-kafka', 'connexion', 'constantly', 'construct',
83
+ 'constructs', 'contextlib2', 'contourpy', 'cookiecutter', 'coolname', 'courlan', 'coverage',
84
+ 'cramjam', 'crashtest', 'crc32c', 'crcmod', 'crewai', 'crewai-tools', 'cron-descriptor',
85
+ 'croniter', 'cronsim', 'cryptography', 'cssselect', 'cssselect2', 'cssutils', 'ctranslate2',
86
+ 'cuda-bindings', 'cuda-core', 'cuda-pathfinder', 'cuda-python', 'cuda-toolkit', 'curl-cffi',
87
+ 'curlify', 'cvxpy', 'cycler', 'cyclonedx-python-lib', 'cyclopts', 'cymem', 'cython',
88
+ 'cytoolz', 'dacite', 'daff', 'daft', 'dagster', 'dagster-aws', 'dagster-graphql',
89
+ 'dagster-pipes', 'dagster-postgres', 'dagster-shared', 'dagster-webserver', 'daphne',
90
+ 'dash', 'dask', 'dask-expr', 'databricks-agents', 'databricks-cli', 'databricks-connect',
91
+ 'databricks-labs-blueprint', 'databricks-labs-dqx', 'databricks-labs-lsql',
92
+ 'databricks-sdk', 'databricks-sql-connector', 'databricks-sqlalchemy', 'dataclasses',
93
+ 'dataclasses-json', 'datadog', 'datadog-api-client', 'datamodel-code-generator',
94
+ 'dataproperty', 'datasets', 'datasketch', 'dateparser', 'datetime', 'daytona',
95
+ 'daytona-analytics-api-client', 'daytona-analytics-api-client-async', 'daytona-api-client',
96
+ 'daytona-api-client-async', 'daytona-toolbox-api-client',
97
+ 'daytona-toolbox-api-client-async', 'db-dtypes', 'dbt-adapters', 'dbt-bigquery',
98
+ 'dbt-common', 'dbt-core', 'dbt-databricks', 'dbt-extractor', 'dbt-postgres', 'dbt-protos',
99
+ 'dbt-semantic-interfaces', 'dbt-snowflake', 'dbt-spark', 'ddgs', 'ddtrace', 'debugpy',
100
+ 'decorator', 'deepagents', 'deepdiff', 'deepmerge', 'defusedxml', 'delta-spark',
101
+ 'deltalake', 'dep-logic', 'dependency-groups', 'dependency-injector', 'deprecated',
102
+ 'deprecation', 'deptry', 'detect-installer', 'detect-secrets', 'diagrams', 'dictdiffer',
103
+ 'diff-cover', 'diffusers', 'dill', 'dirhash', 'dirtyjson', 'discord-py', 'diskcache',
104
+ 'disposable-email-domains', 'distlib', 'distributed', 'distro', 'dj-database-url', 'django',
105
+ 'django-celery-beat', 'django-cors-headers', 'django-debug-toolbar', 'django-environ',
106
+ 'django-extensions', 'django-filter', 'django-ipware', 'django-phonenumber-field',
107
+ 'django-redis', 'django-storages', 'django-stubs', 'django-stubs-ext',
108
+ 'django-timezone-field', 'djangorestframework', 'djangorestframework-simplejwt',
109
+ 'djangorestframework-stubs', 'dlt', 'dnspython', 'docker', 'docker-pycreds',
110
+ 'dockerfile-parse', 'docling', 'docling-core', 'docopt', 'docstring-parser', 'docutils',
111
+ 'dotenv', 'dpath', 'drf-spectacular', 'dspy', 'duckdb', 'dulwich', 'dunamai', 'durationpy',
112
+ 'dynaconf', 'e2b', 'easygui', 'ebcdic', 'ecdsa', 'edge-tts', 'editables', 'editorconfig',
113
+ 'einops', 'elastic-transport', 'elasticsearch', 'elasticsearch-dsl', 'elementpath',
114
+ 'elevenlabs', 'email-validator', 'emoji', 'entrypoints', 'enum-compat', 'enum34', 'envier',
115
+ 'environs', 'et-xmlfile', 'eth-abi', 'eth-account', 'eth-hash', 'eth-keyfile', 'eth-keys',
116
+ 'eth-rlp', 'eth-typing', 'eth-utils', 'etils', 'eval-type-backport', 'eventlet', 'events',
117
+ 'exa-py', 'exceptiongroup', 'exchange-calendars', 'execnet', 'executing', 'expiringdict',
118
+ 'expression', 'extract-msg', 'fabric', 'face', 'facebook-business', 'factory-boy',
119
+ 'faiss-cpu', 'fake-useragent', 'faker', 'fakeredis', 'fastapi', 'fastapi-cli',
120
+ 'fastapi-cloud-cli', 'fastapi-mcp', 'fastapi-sso', 'fastar', 'fastavro', 'fastcore',
121
+ 'fastembed', 'fasteners', 'faster-whisper', 'fastf1', 'fastjsonschema', 'fastmcp',
122
+ 'fastmcp-slim', 'fastparquet', 'fastspec', 'fasttransport', 'fastuuid', 'feedparser',
123
+ 'feedparser-sgmllib', 'fetch-use', 'ffmpeg-python', 'filelock', 'filetype', 'findpython',
124
+ 'fiona', 'fire', 'firebase-admin', 'firecrawl-anydoc', 'firecrawl-py', 'flake8', 'flask',
125
+ 'flask-appbuilder', 'flask-babel', 'flask-caching', 'flask-cors', 'flask-jwt-extended',
126
+ 'flask-limiter', 'flask-login', 'flask-session', 'flask-sqlalchemy', 'flask-wtf',
127
+ 'flatbuffers', 'flexcache', 'flexparser', 'flit', 'flit-core', 'flower', 'fonttools',
128
+ 'fpdf2', 'fqdn', 'freezegun', 'frozendict', 'frozenlist', 'fsspec', 'ftfy', 'func-timeout',
129
+ 'functions-framework', 'funcy', 'furl', 'future', 'fuzzywuzzy', 'gast', 'gcloud-aio-auth',
130
+ 'gcloud-aio-bigquery', 'gcloud-aio-storage', 'gcsfs', 'genai-prices', 'genson',
131
+ 'geographiclib', 'geoip2', 'geomet', 'geopandas', 'geopy', 'gepa', 'gevent',
132
+ 'geventhttpclient', 'gguf', 'ghapi', 'ghp-import', 'gitdb', 'github3-py', 'gitpython',
133
+ 'giturlparse', 'glom', 'google', 'google-adk', 'google-ads', 'google-ai-generativelanguage',
134
+ 'google-analytics-admin', 'google-analytics-data', 'google-api-core',
135
+ 'google-api-python-client', 'google-auth', 'google-auth-httplib2', 'google-auth-oauthlib',
136
+ 'google-cloud-aiplatform', 'google-cloud-alloydb', 'google-cloud-appengine-logging',
137
+ 'google-cloud-audit-log', 'google-cloud-automl', 'google-cloud-batch',
138
+ 'google-cloud-bigquery', 'google-cloud-bigquery-datatransfer',
139
+ 'google-cloud-bigquery-storage', 'google-cloud-bigtable', 'google-cloud-build',
140
+ 'google-cloud-compute', 'google-cloud-container', 'google-cloud-core',
141
+ 'google-cloud-datacatalog', 'google-cloud-dataflow-client', 'google-cloud-dataform',
142
+ 'google-cloud-dataplex', 'google-cloud-dataproc', 'google-cloud-dataproc-metastore',
143
+ 'google-cloud-datastore', 'google-cloud-discoveryengine', 'google-cloud-dlp',
144
+ 'google-cloud-firestore', 'google-cloud-iam', 'google-cloud-kms', 'google-cloud-language',
145
+ 'google-cloud-logging', 'google-cloud-managedkafka', 'google-cloud-memcache',
146
+ 'google-cloud-monitoring', 'google-cloud-orchestration-airflow', 'google-cloud-os-login',
147
+ 'google-cloud-pubsub', 'google-cloud-redis', 'google-cloud-resource-manager',
148
+ 'google-cloud-run', 'google-cloud-secret-manager', 'google-cloud-spanner',
149
+ 'google-cloud-speech', 'google-cloud-storage', 'google-cloud-storage-control',
150
+ 'google-cloud-storage-transfer', 'google-cloud-tasks', 'google-cloud-texttospeech',
151
+ 'google-cloud-trace', 'google-cloud-translate', 'google-cloud-videointelligence',
152
+ 'google-cloud-vision', 'google-cloud-workflows', 'google-crc32c', 'google-genai',
153
+ 'google-generativeai', 'google-pasta', 'google-re2', 'google-resumable-media',
154
+ 'googleapis-common-protos', 'gprof2dot', 'gql', 'gradio', 'gradio-client', 'granian',
155
+ 'graphene', 'graphql-core', 'graphql-relay', 'graphviz', 'great-expectations', 'greenback',
156
+ 'greenlet', 'gremlinpython', 'griffe', 'griffecli', 'griffelib', 'grimp', 'groq',
157
+ 'grpc-google-iam-v1', 'grpc-interceptor', 'grpcio', 'grpcio-gcp', 'grpcio-health-checking',
158
+ 'grpcio-reflection', 'grpcio-status', 'grpcio-tools', 'grpclib', 'gspread', 'gunicorn',
159
+ 'gymnasium', 'h11', 'h2', 'h3', 'h5py', 'habluetooth', 'harbor', 'harbor-rewardkit',
160
+ 'hatch', 'hatch-fancy-pypi-readme', 'hatch-vcs', 'hatchling', 'hexbytes', 'hf-xet',
161
+ 'highspy', 'hiredis', 'holidays', 'hpack', 'html2text', 'html5lib', 'htmldate', 'httpcore',
162
+ 'httpcore2', 'httplib2', 'httptools', 'httpx', 'httpx-sse', 'httpx-ws', 'httpx2',
163
+ 'httpx2-jsfetch', 'huey', 'huggingface-hub', 'humanfriendly', 'humanize', 'hvac',
164
+ 'hydra-core', 'hypercorn', 'hyperframe', 'hyperlink', 'hypothesis', 'icalendar', 'icdiff',
165
+ 'id', 'identify', 'idna', 'ifaddr', 'ijson', 'imagehash', 'imageio', 'imageio-ffmpeg',
166
+ 'imagesize', 'imbalanced-learn', 'immutabledict', 'import-linter', 'importlib-metadata',
167
+ 'importlib-resources', 'impyla', 'incremental', 'inflate64', 'inflect', 'inflection',
168
+ 'influxdb-client', 'iniconfig', 'inputimeout', 'inquirerpy', 'inspect-ai', 'installer',
169
+ 'instructor', 'intervaltree', 'invoke', 'ipdb', 'ipykernel', 'ipython', 'ipython-genutils',
170
+ 'ipython-pygments-lexers', 'ipywidgets', 'iso8601', 'isodate', 'isoduration', 'isort',
171
+ 'itsdangerous', 'jaraco-classes', 'jaraco-context', 'jaraco-functools', 'jax', 'jaxlib',
172
+ 'jaydebeapi', 'jedi', 'jeepney', 'jellyfish', 'jinja2', 'jinja2-humanize-extension',
173
+ 'jinxed', 'jira', 'jiter', 'jmespath', 'joblib', 'joserfc', 'jpype1', 'jq', 'jsbeautifier',
174
+ 'jsii', 'json-repair', 'json-rpc', 'json5', 'jsonconversion', 'jsondiff', 'jsonlines',
175
+ 'jsonpatch', 'jsonpath-ng', 'jsonpath-python', 'jsonpickle', 'jsonpointer', 'jsonref',
176
+ 'jsonschema', 'jsonschema-path', 'jsonschema-rs', 'jsonschema-specifications', 'junit-xml',
177
+ 'junitparser', 'jupyter', 'jupyter-builder', 'jupyter-client', 'jupyter-console',
178
+ 'jupyter-core', 'jupyter-events', 'jupyter-lsp', 'jupyter-server',
179
+ 'jupyter-server-terminals', 'jupyterlab', 'jupyterlab-pygments', 'jupyterlab-server',
180
+ 'jupyterlab-widgets', 'justext', 'jwcrypto', 'kafka-python', 'kaitaistruct', 'kaleido',
181
+ 'keras', 'kestra', 'keyring', 'keyrings-google-artifactregistry-auth', 'kfp', 'kgb',
182
+ 'kiwisolver', 'knack', 'kombu', 'korean-lunar-calendar', 'kubernetes', 'kubernetes-asyncio',
183
+ 'lance-namespace', 'lance-namespace-urllib3-client', 'lancedb', 'langchain',
184
+ 'langchain-anthropic', 'langchain-aws', 'langchain-classic', 'langchain-community',
185
+ 'langchain-core', 'langchain-google-community', 'langchain-google-genai',
186
+ 'langchain-google-vertexai', 'langchain-mcp-adapters', 'langchain-openai',
187
+ 'langchain-protocol', 'langchain-text-splitters', 'langcodes', 'langdetect', 'langfuse',
188
+ 'langgraph', 'langgraph-api', 'langgraph-checkpoint', 'langgraph-checkpoint-postgres',
189
+ 'langgraph-prebuilt', 'langgraph-sdk', 'langsmith', 'lark', 'launchdarkly-eventsource',
190
+ 'launchdarkly-server-sdk', 'lazy-loader', 'lazy-object-proxy', 'ldap3', 'leather',
191
+ 'levenshtein', 'libclang', 'libcst', 'librosa', 'librt', 'libtmux', 'license-expression',
192
+ 'lightgbm', 'lightning', 'lightning-utilities', 'limits', 'line-bot-sdk', 'linkify-it-py',
193
+ 'litellm', 'litellm-enterprise', 'litellm-proxy-extras', 'livekit-agents',
194
+ 'livekit-protocol', 'llama-cloud', 'llama-cloud-services', 'llama-index',
195
+ 'llama-index-core', 'llama-index-embeddings-openai',
196
+ 'llama-index-indices-managed-llama-cloud', 'llama-index-instrumentation',
197
+ 'llama-index-llms-openai', 'llama-index-readers-llama-parse', 'llama-index-workflows',
198
+ 'llama-parse', 'llguidance', 'llvmlite', 'lmnr', 'lmnr-claude-code-proxy', 'locket',
199
+ 'lockfile', 'locust', 'logfire', 'logfire-api', 'loguru', 'looker-sdk', 'lru-dict', 'lupa',
200
+ 'lxml', 'lxml-html-clean', 'lz4', 'magika', 'makefun', 'mako', 'mammoth', 'mando', 'mangum',
201
+ 'markdown', 'markdown-it-py', 'markdown2', 'markdownify', 'markitdown', 'marko',
202
+ 'markupsafe', 'marshmallow', 'marshmallow-dataclass', 'marshmallow-enum',
203
+ 'marshmallow-oneofschema', 'marshmallow-sqlalchemy', 'mashumaro', 'matplotlib',
204
+ 'matplotlib-inline', 'maturin', 'maxminddb', 'mbstrdecoder', 'mccabe', 'mcp', 'mcp-types',
205
+ 'mdit-py-plugins', 'mdurl', 'memory-profiler', 'memray', 'mergedeep', 'meson',
206
+ 'meson-python', 'methodtools', 'metricflow', 'microsoft-kiota-abstractions',
207
+ 'microsoft-kiota-authentication-azure', 'microsoft-kiota-http',
208
+ 'microsoft-kiota-serialization-form', 'microsoft-kiota-serialization-json',
209
+ 'microsoft-kiota-serialization-multipart', 'microsoft-kiota-serialization-text',
210
+ 'mini-swe-agent', 'minio', 'mistral-common', 'mistral-vibe', 'mistralai', 'mistune',
211
+ 'mitmproxy', 'mitmproxy-rs', 'mixpanel', 'mkdocs', 'mkdocs-autorefs', 'mkdocs-get-deps',
212
+ 'mkdocs-material', 'mkdocs-material-extensions', 'mkdocstrings', 'mkdocstrings-python',
213
+ 'ml-dtypes', 'mlflow', 'mlflow-skinny', 'mlflow-tracing', 'mmh3', 'mock', 'modal',
214
+ 'modelscope', 'mongomock', 'monotonic', 'more-itertools', 'moto', 'motor', 'moviepy',
215
+ 'mpmath', 'msal', 'msal-extensions', 'msgpack', 'msgraph-core', 'msgraph-sdk', 'msgspec',
216
+ 'msoffcrypto-tool', 'msrest', 'msrestazure', 'multidict', 'multiprocess', 'multitasking',
217
+ 'multivolumefile', 'murmurhash', 'mutagen', 'mypy', 'mypy-boto3-cloudformation',
218
+ 'mypy-boto3-dynamodb', 'mypy-boto3-ec2', 'mypy-boto3-glue', 'mypy-boto3-lambda',
219
+ 'mypy-boto3-rds', 'mypy-boto3-s3', 'mypy-boto3-secretsmanager', 'mypy-boto3-sqs',
220
+ 'mypy-boto3-sts', 'mypy-extensions', 'mypy-protobuf', 'mysql-connector-python',
221
+ 'mysqlclient', 'myst-parser', 'namex', 'nanoid', 'narwhals', 'natsort', 'nbclient',
222
+ 'nbconvert', 'nbformat', 'ndg-httpsclient', 'nemo-relay', 'neo4j', 'nest-asyncio',
223
+ 'nest-asyncio2', 'netaddr', 'networkx', 'nexus-rpc', 'nh3', 'ninja', 'nltk', 'nodeenv',
224
+ 'nodejs-wheel-binaries', 'nose', 'notebook', 'notebook-shim', 'nox', 'num2words', 'numba',
225
+ 'numcodecs', 'numexpr', 'numpy', 'numpy-financial', 'nvidia-cublas', 'nvidia-cublas-cu12',
226
+ 'nvidia-cuda-cupti', 'nvidia-cuda-cupti-cu12', 'nvidia-cuda-nvrtc',
227
+ 'nvidia-cuda-nvrtc-cu12', 'nvidia-cuda-runtime', 'nvidia-cuda-runtime-cu12',
228
+ 'nvidia-cudnn-cu12', 'nvidia-cudnn-cu13', 'nvidia-cufft', 'nvidia-cufft-cu12',
229
+ 'nvidia-cufile', 'nvidia-cufile-cu12', 'nvidia-curand', 'nvidia-curand-cu12',
230
+ 'nvidia-cusolver', 'nvidia-cusolver-cu12', 'nvidia-cusparse', 'nvidia-cusparse-cu12',
231
+ 'nvidia-cusparselt-cu12', 'nvidia-cusparselt-cu13', 'nvidia-cutlass-dsl',
232
+ 'nvidia-cutlass-dsl-libs-base', 'nvidia-ml-py', 'nvidia-nccl-cu12', 'nvidia-nccl-cu13',
233
+ 'nvidia-nvjitlink', 'nvidia-nvjitlink-cu12', 'nvidia-nvshmem-cu12', 'nvidia-nvshmem-cu13',
234
+ 'nvidia-nvtx', 'nvidia-nvtx-cu12', 'oauth2client', 'oauthlib', 'obstore', 'oci',
235
+ 'office365-rest-python-client', 'oldest-supported-numpy', 'olefile', 'oletools', 'ollama',
236
+ 'omegaconf', 'onnx', 'onnxruntime', 'openai', 'openai-agents', 'openai-harmony',
237
+ 'openapi-pydantic', 'openapi-schema-validator', 'openapi-spec-validator', 'opencensus',
238
+ 'opencensus-context', 'opencensus-ext-azure', 'opencv-contrib-python', 'opencv-python',
239
+ 'opencv-python-headless', 'openhands-sdk', 'openhands-tools',
240
+ 'openinference-instrumentation', 'openinference-semantic-conventions',
241
+ 'openlineage-integration-common', 'openlineage-python', 'openlineage-sql', 'openpyxl',
242
+ 'opensearch-protobufs', 'opensearch-py', 'opentelemetry-api', 'opentelemetry-distro',
243
+ 'opentelemetry-exporter-gcp-logging', 'opentelemetry-exporter-gcp-monitoring',
244
+ 'opentelemetry-exporter-gcp-trace', 'opentelemetry-exporter-otlp',
245
+ 'opentelemetry-exporter-otlp-proto-common', 'opentelemetry-exporter-otlp-proto-grpc',
246
+ 'opentelemetry-exporter-otlp-proto-http', 'opentelemetry-exporter-prometheus',
247
+ 'opentelemetry-instrumentation', 'opentelemetry-instrumentation-aiohttp-client',
248
+ 'opentelemetry-instrumentation-asgi', 'opentelemetry-instrumentation-asyncio',
249
+ 'opentelemetry-instrumentation-asyncpg', 'opentelemetry-instrumentation-boto3sqs',
250
+ 'opentelemetry-instrumentation-botocore', 'opentelemetry-instrumentation-celery',
251
+ 'opentelemetry-instrumentation-dbapi', 'opentelemetry-instrumentation-django',
252
+ 'opentelemetry-instrumentation-fastapi', 'opentelemetry-instrumentation-flask',
253
+ 'opentelemetry-instrumentation-google-genai', 'opentelemetry-instrumentation-grpc',
254
+ 'opentelemetry-instrumentation-httpx', 'opentelemetry-instrumentation-kafka-python',
255
+ 'opentelemetry-instrumentation-logging', 'opentelemetry-instrumentation-psycopg',
256
+ 'opentelemetry-instrumentation-psycopg2', 'opentelemetry-instrumentation-pymongo',
257
+ 'opentelemetry-instrumentation-redis', 'opentelemetry-instrumentation-requests',
258
+ 'opentelemetry-instrumentation-sqlalchemy', 'opentelemetry-instrumentation-sqlite3',
259
+ 'opentelemetry-instrumentation-starlette', 'opentelemetry-instrumentation-system-metrics',
260
+ 'opentelemetry-instrumentation-threading', 'opentelemetry-instrumentation-urllib',
261
+ 'opentelemetry-instrumentation-urllib3', 'opentelemetry-instrumentation-wsgi',
262
+ 'opentelemetry-propagator-aws-xray', 'opentelemetry-proto',
263
+ 'opentelemetry-resource-detector-azure', 'opentelemetry-resourcedetector-gcp',
264
+ 'opentelemetry-sdk', 'opentelemetry-sdk-extension-aws',
265
+ 'opentelemetry-semantic-conventions', 'opentelemetry-semantic-conventions-ai',
266
+ 'opentelemetry-util-genai', 'opentelemetry-util-http', 'opt-einsum', 'optree', 'optuna',
267
+ 'oracledb', 'orbax-checkpoint', 'ordered-set', 'orderedmultidict', 'orderly-set', 'orjson',
268
+ 'ormsgpack', 'ortools', 'oscrypto', 'osqp', 'oss2', 'outcome', 'overrides',
269
+ 'packageurl-python', 'packaging', 'paginate', 'paho-mqtt', 'pamqp', 'pandas', 'pandas-gbq',
270
+ 'pandas-stubs', 'pandera', 'pandocfilters', 'papermill', 'parameterized', 'paramiko',
271
+ 'parse', 'parse-type', 'parsedatetime', 'parsimonious', 'parso', 'partd',
272
+ 'partial-json-parser', 'parver', 'passlib', 'pastel', 'patchelf', 'pathable', 'pathlib',
273
+ 'pathlib-abc', 'pathos', 'pathspec', 'pathvalidate', 'patsy', 'pbr', 'pbs-installer',
274
+ 'pcodedmp', 'pdbr', 'pdf2image', 'pdfminer-six', 'pdfplumber', 'pdm', 'peewee', 'pefile',
275
+ 'peft', 'pendulum', 'pep517', 'pex', 'pexpect', 'pfzy', 'pg8000', 'pglast', 'pgpy',
276
+ 'pgvector', 'phonenumbers', 'pi-heif', 'pickleshare', 'pika', 'pikepdf', 'pillow',
277
+ 'pillow-heif', 'pinecone', 'pinotdb', 'pint', 'pip', 'pip-api', 'pip-audit',
278
+ 'pip-requirements-parser', 'pip-tools', 'pipdeptree', 'pipenv', 'pipx', 'pkgconfig',
279
+ 'pkginfo', 'pkgutil-resolve-name', 'platformdirs', 'playwright', 'plotly', 'pluggy',
280
+ 'plumbum', 'ply', 'poethepoet', 'poetry', 'poetry-core', 'poetry-plugin-export', 'polars',
281
+ 'polars-runtime-32', 'polib', 'polyfactory', 'pooch', 'port-for', 'portalocker',
282
+ 'postgrest', 'posthog', 'pox', 'ppft', 'pprintpp', 'prance', 'pre-commit', 'prefect',
283
+ 'prefect-aws', 'prek', 'preshed', 'presidio-analyzer', 'prettytable', 'primp', 'priority',
284
+ 'prison', 'probableparsing', 'proglog', 'progressbar2', 'prometheus-client',
285
+ 'prometheus-fastapi-instrumentator', 'prompt-toolkit', 'propcache', 'prophet', 'protego',
286
+ 'proto-plus', 'protobuf', 'protobuf3-to-dict', 'psutil', 'psycopg', 'psycopg-binary',
287
+ 'psycopg-pool', 'psycopg2', 'psycopg2-binary', 'ptyprocess', 'publication', 'publicsuffix2',
288
+ 'pulp', 'pulumi', 'pulumi-aws', 'pure-eval', 'pure-sasl', 'puremagic', 'py', 'py-cpuinfo',
289
+ 'py-key-value-aio', 'py-key-value-shared', 'py-partiql-parser', 'py-serializable', 'py-spy',
290
+ 'py-vapid', 'py4j', 'py7zr', 'pyahocorasick', 'pyaml', 'pyarrow', 'pyarrow-hotfix',
291
+ 'pyasn1', 'pyasn1-modules', 'pyathena', 'pybase64', 'pybcj', 'pybind11', 'pybreaker',
292
+ 'pycares', 'pycarlo', 'pyclipper', 'pycodestyle', 'pycomposefile', 'pycountry', 'pycparser',
293
+ 'pycrypto', 'pycryptodome', 'pycryptodomex', 'pydantic', 'pydantic-ai', 'pydantic-ai-slim',
294
+ 'pydantic-core', 'pydantic-evals', 'pydantic-extra-types', 'pydantic-graph',
295
+ 'pydantic-settings', 'pydash', 'pydata-google-auth', 'pydeck', 'pydeequ', 'pydocket',
296
+ 'pydot', 'pydub', 'pydyf', 'pyee', 'pyelftools', 'pyfiglet', 'pyflakes', 'pygit2',
297
+ 'pygithub', 'pygments', 'pygtrie', 'pyhanko', 'pyhanko-certvalidator', 'pyhcl', 'pyhive',
298
+ 'pyhumps', 'pyiceberg', 'pyiceberg-core', 'pyinstaller', 'pyinstaller-hooks-contrib',
299
+ 'pyinstrument', 'pyjwt', 'pylatexenc', 'pylint', 'pylsqpack', 'pyluach',
300
+ 'pymdown-extensions', 'pymilvus', 'pymongo', 'pympler', 'pymssql', 'pymsteams', 'pymupdf',
301
+ 'pymupdf-layout', 'pymupdf4llm', 'pymysql', 'pynacl', 'pynndescent', 'pyodbc', 'pyogrio',
302
+ 'pyopengl', 'pyopenssl', 'pyotp', 'pypandoc', 'pyparsing', 'pypdf', 'pypdf2', 'pypdfium2',
303
+ 'pyperclip', 'pyphen', 'pypika', 'pypng', 'pyppmd', 'pyproj', 'pyproject-api',
304
+ 'pyproject-hooks', 'pyproject-metadata', 'pyrate-limiter', 'pyreadline3', 'pyrefly',
305
+ 'pyrfc3339', 'pyright', 'pyroaring', 'pyroscope-io', 'pyrsistent', 'pyserial', 'pysftp',
306
+ 'pysocks', 'pyspark', 'pyspnego', 'pytablewriter', 'pytesseract', 'pytest',
307
+ 'pytest-aiohttp', 'pytest-asyncio', 'pytest-base-url', 'pytest-benchmark', 'pytest-cov',
308
+ 'pytest-custom-exit-code', 'pytest-django', 'pytest-env', 'pytest-forked',
309
+ 'pytest-homeassistant-custom-component', 'pytest-html', 'pytest-httpx', 'pytest-icdiff',
310
+ 'pytest-json-ctrf', 'pytest-json-report', 'pytest-metadata', 'pytest-mock', 'pytest-order',
311
+ 'pytest-playwright', 'pytest-postgresql', 'pytest-randomly', 'pytest-repeat',
312
+ 'pytest-rerunfailures', 'pytest-runner', 'pytest-socket', 'pytest-split', 'pytest-sugar',
313
+ 'pytest-timeout', 'pytest-unordered', 'pytest-xdist', 'python-bidi', 'python-box',
314
+ 'python-calamine', 'python-crfsuite', 'python-crontab', 'python-daemon', 'python-dateutil',
315
+ 'python-decouple', 'python-discovery', 'python-docx', 'python-dotenv', 'python-engineio',
316
+ 'python-frontmatter', 'python-gitlab', 'python-gnupg', 'python-hcl2', 'python-http-client',
317
+ 'python-jenkins', 'python-jose', 'python-json-logger', 'python-keycloak',
318
+ 'python-levenshtein', 'python-magic', 'python-multipart', 'python-on-whales', 'python-pptx',
319
+ 'python-slugify', 'python-snappy', 'python-socketio', 'python-socks', 'python-stdnum',
320
+ 'python-tds', 'python-telegram-bot', 'python-ulid', 'python-utils', 'python3-openid',
321
+ 'python3-saml', 'pytimeparse', 'pytokens', 'pytorch-lightning', 'pytz', 'pytzdata',
322
+ 'pyvespa', 'pywavelets', 'pywebpush', 'pywin32', 'pywin32-ctypes', 'pyxlsb', 'pyyaml',
323
+ 'pyyaml-env-tag', 'pyyaml-ft', 'pyzipper', 'pyzmq', 'pyzstd', 'qdrant-client', 'qrcode',
324
+ 'quack-kernels', 'questionary', 'radon', 'rank-bm25', 'rapidfuzz', 'rasterio', 'ratelimit',
325
+ 'ray', 'rdflib', 'reactivex', 'readchar', 'readme-renderer', 'realtime', 'redis',
326
+ 'redshift-connector', 'referencing', 'regex', 'reportlab', 'requests', 'requests-aws4auth',
327
+ 'requests-cache', 'requests-file', 'requests-mock', 'requests-ntlm', 'requests-oauthlib',
328
+ 'requests-toolbelt', 'requirements-parser', 'resend', 'resolvelib', 'responses', 'respx',
329
+ 'restrictedpython', 'restructuredtext-lint', 'retry', 'retrying', 'rfc3339-validator',
330
+ 'rfc3986', 'rfc3986-validator', 'rfc3987-syntax', 'rich', 'rich-argparse', 'rich-click',
331
+ 'rich-rst', 'rich-toolkit', 'rignore', 'rlp', 'roman-numerals', 'rouge-score', 'rpds-py',
332
+ 'rq', 'rsa', 'rtfde', 'rtree', 'ruamel-yaml', 'ruamel-yaml-clib', 'ruff', 'rustworkx',
333
+ 's3fs', 's3transfer', 'safehttpx', 'safetensors', 'sagemaker', 'sagemaker-core',
334
+ 'sagemaker-studio', 'scantree', 'schedule', 'schema', 'schemathesis', 'scikit-build-core',
335
+ 'scikit-image', 'scikit-learn', 'scipy', 'scp', 'scramp', 'screeninfo', 'scs', 'seaborn',
336
+ 'secretstorage', 'segment-analytics-python', 'selectolax', 'selenium', 'semantic-version',
337
+ 'semgrep', 'semver', 'send2trash', 'sendgrid', 'sentence-transformers', 'sentencepiece',
338
+ 'sentinels', 'sentry-sdk', 'service-identity', 'setproctitle', 'setuptools',
339
+ 'setuptools-rust', 'setuptools-scm', 'sglang', 'sgmllib3k', 'sh', 'shap', 'shapely',
340
+ 'shellingham', 'shortuuid', 'simple-gcp-object-downloader', 'simple-salesforce',
341
+ 'simple-websocket', 'simpleeval', 'simplejson', 'singer-sdk', 'six', 'skops', 'slack-bolt',
342
+ 'slack-sdk', 'slackclient', 'slicer', 'slowapi', 'smart-open', 'smbprotocol',
343
+ 'smdebug-rulesconfig', 'smmap', 'sniffio', 'snowballstemmer', 'snowflake-connector-python',
344
+ 'snowflake-core', 'snowflake-snowpark-python', 'snowflake-sqlalchemy', 'snowplow-tracker',
345
+ 'social-auth-app-django', 'social-auth-core', 'socksio', 'sortedcontainers', 'sounddevice',
346
+ 'soundfile', 'soupsieve', 'soxr', 'spacy', 'spacy-legacy', 'spacy-loggers', 'sparklines',
347
+ 'speechrecognition', 'sphinx', 'sphinx-autodoc-typehints', 'sphinx-copybutton',
348
+ 'sphinx-design', 'sphinx-rtd-theme', 'sphinxcontrib-applehelp', 'sphinxcontrib-devhelp',
349
+ 'sphinxcontrib-htmlhelp', 'sphinxcontrib-jquery', 'sphinxcontrib-jsmath',
350
+ 'sphinxcontrib-mermaid', 'sphinxcontrib-qthelp', 'sphinxcontrib-serializinghtml',
351
+ 'sql-metadata', 'sqlalchemy', 'sqlalchemy-bigquery', 'sqlalchemy-spanner',
352
+ 'sqlalchemy-utils', 'sqlfluff', 'sqlglot', 'sqlite-vec', 'sqlmodel', 'sqlparams',
353
+ 'sqlparse', 'srsly', 'sse-starlette', 'sseclient-py', 'sshtunnel', 'stack-data', 'stamina',
354
+ 'stanio', 'starkbank-ecdsa', 'starlette', 'statsd', 'statsmodels', 'std-uritemplate',
355
+ 'stevedore', 'storage3', 'strands-agents', 'strawberry-graphql', 'streamlit', 'strenum',
356
+ 'strictyaml', 'stringcase', 'stripe', 'striprtf', 'structlog', 'subprocess-tee', 'supabase',
357
+ 'supabase-auth', 'supabase-functions', 'supervisor', 'svcs', 'svglib', 'svix', 'swebench',
358
+ 'swesmith', 'swifter', 'sympy', 'synchronicity', 'syrupy', 'tableauserverclient',
359
+ 'tabledata', 'tabulate', 'tavily-python', 'tblib', 'temporalio', 'tenacity', 'tensorboard',
360
+ 'tensorboard-data-server', 'tensorflow', 'tensorflow-estimator',
361
+ 'tensorflow-io-gcs-filesystem', 'teradatasql', 'termcolor', 'terminado', 'terminaltables',
362
+ 'testcontainers', 'text-unidecode', 'texttable', 'textual', 'textual-speedups', 'thefuzz',
363
+ 'thinc', 'threadpoolctl', 'thrift', 'thrift-sasl', 'tifffile', 'tiktoken', 'time-machine',
364
+ 'timezonefinder', 'timm', 'tinycss2', 'tinyhtml5', 'tld', 'tldextract', 'tokenize-rt',
365
+ 'tokenizers', 'tom-swe', 'toml', 'tomli', 'tomli-w', 'tomlkit', 'toolz', 'toons',
366
+ 'toposort', 'torch', 'torchaudio', 'torchmetrics', 'torchvision', 'tornado', 'tox',
367
+ 'tox-uv', 'tqdm', 'trafilatura', 'traitlets', 'transformers', 'tree-sitter',
368
+ 'tree-sitter-bash', 'tree-sitter-c', 'tree-sitter-c-sharp', 'tree-sitter-embedded-template',
369
+ 'tree-sitter-go', 'tree-sitter-java', 'tree-sitter-javascript', 'tree-sitter-language-pack',
370
+ 'tree-sitter-languages', 'tree-sitter-php', 'tree-sitter-python', 'tree-sitter-ruby',
371
+ 'tree-sitter-rust', 'tree-sitter-typescript', 'tree-sitter-yaml', 'trimesh', 'trino',
372
+ 'trio', 'trio-websocket', 'triton', 'tritonclient', 'trove-classifiers', 'truststore',
373
+ 'twilio', 'twine', 'twisted', 'txaio', 'ty', 'typedload', 'typeguard', 'typepy', 'typer',
374
+ 'typer-slim', 'types-aioboto3', 'types-aiobotocore', 'types-aiobotocore-s3',
375
+ 'types-aiofiles', 'types-awscrt', 'types-boto3', 'types-boto3-s3', 'types-cachetools',
376
+ 'types-certifi', 'types-cffi', 'types-croniter', 'types-deprecated', 'types-docutils',
377
+ 'types-html5lib', 'types-jsonschema', 'types-markdown', 'types-openpyxl', 'types-paramiko',
378
+ 'types-protobuf', 'types-psutil', 'types-psycopg2', 'types-pymysql', 'types-pyopenssl',
379
+ 'types-python-dateutil', 'types-python-slugify', 'types-pytz', 'types-pyyaml',
380
+ 'types-redis', 'types-requests', 'types-retry', 'types-s3transfer', 'types-setuptools',
381
+ 'types-tabulate', 'types-toml', 'types-tqdm', 'types-urllib3', 'types-webencodings',
382
+ 'typing-extensions', 'typing-inspect', 'typing-inspection', 'tyro', 'tzdata', 'tzlocal',
383
+ 'ua-parser', 'ua-parser-builtins', 'uamqp', 'uc-micro-py', 'ujson', 'ultralytics',
384
+ 'ultralytics-thop', 'umap-learn', 'uncalled-for', 'unearth', 'unicodecsv', 'unidecode',
385
+ 'unidiff', 'unittest-xml-reporting', 'universal-pathlib', 'unstructured-client',
386
+ 'uri-template', 'uritemplate', 'uritools', 'url-normalize', 'urllib3', 'urwid', 'usaddress',
387
+ 'user-agents', 'userpath', 'uuid-utils', 'uuid6', 'uuid7', 'uv', 'uv-build',
388
+ 'uv-dynamic-versioning', 'uvicorn', 'uvicorn-worker', 'uvloop', 'validators', 'vcrpy',
389
+ 'vcs-versioning', 'vine', 'virtualenv', 'voluptuous', 'vulture', 'w3lib', 'waitress',
390
+ 'wandb', 'wasabi', 'watchdog', 'watchfiles', 'watchtower', 'wcmatch', 'wcwidth', 'weasel',
391
+ 'weasyprint', 'weaviate-client', 'web3', 'webauthn', 'webcolors', 'webdriver-manager',
392
+ 'webencodings', 'webob', 'websocket-client', 'websockets', 'werkzeug', 'wheel', 'whenever',
393
+ 'whitenoise', 'widgetsnbextension', 'wikipedia-api', 'wirerope', 'workos', 'wrapt',
394
+ 'wsproto', 'wtforms', 'xarray', 'xattr', 'xgboost', 'xgrammar', 'xlrd', 'xlsxwriter',
395
+ 'xlwt', 'xmlschema', 'xmlsec', 'xmltodict', 'xxhash', 'xyzservices', 'yamllint',
396
+ 'yandexcloud', 'yapf', 'yarl', 'ydb', 'yfinance', 'youtube-transcript-api', 'yt-dlp',
397
+ 'z3-solver', 'zarr', 'zeep', 'zipp', 'zope-event', 'zope-interface', 'zopfli', 'zstandard',
398
+ 'zstd', 'zxcvbn',
399
+ ])
ghostpkg/registries.py ADDED
@@ -0,0 +1,130 @@
1
+ """Registry clients. Standard library only -- ghostpkg has no dependencies.
2
+
3
+ A supply-chain security tool that pulls in a dependency tree is a poor joke,
4
+ so this module deliberately uses urllib rather than requests.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import urllib.error
11
+ import urllib.parse
12
+ import urllib.request
13
+ from dataclasses import dataclass
14
+ from datetime import datetime, timezone
15
+
16
+ USER_AGENT = "ghostpkg/0.1 (+https://github.com/m1rwana12/ghostpkg)"
17
+ TIMEOUT = 15
18
+
19
+
20
+ class RegistryError(RuntimeError):
21
+ """The registry could not be reached or returned something unusable."""
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class PackageFacts:
26
+ """What a registry tells us about a name. `exists=False` means 404."""
27
+
28
+ name: str
29
+ ecosystem: str
30
+ exists: bool
31
+ age_days: int | None = None
32
+ release_count: int = 0
33
+ has_repo_url: bool = False
34
+ latest_version: str | None = None
35
+ summary: str | None = None
36
+
37
+
38
+ def _get_json(url: str) -> dict | None:
39
+ """Fetch and decode JSON. Returns None on a clean 404."""
40
+ request = urllib.request.Request(url, headers={"User-Agent": USER_AGENT})
41
+ try:
42
+ with urllib.request.urlopen(request, timeout=TIMEOUT) as response:
43
+ return json.loads(response.read().decode("utf-8"))
44
+ except urllib.error.HTTPError as exc:
45
+ if exc.code == 404:
46
+ return None
47
+ raise RegistryError(f"{url} returned HTTP {exc.code}") from exc
48
+ except urllib.error.URLError as exc:
49
+ raise RegistryError(f"could not reach {url}: {exc.reason}") from exc
50
+ except json.JSONDecodeError as exc:
51
+ raise RegistryError(f"{url} returned malformed JSON") from exc
52
+
53
+
54
+ def _age_in_days(iso_timestamp: str) -> int | None:
55
+ try:
56
+ moment = datetime.fromisoformat(iso_timestamp.replace("Z", "+00:00"))
57
+ except ValueError:
58
+ return None
59
+ return (datetime.now(timezone.utc) - moment).days
60
+
61
+
62
+ def fetch_pypi(name: str) -> PackageFacts:
63
+ quoted = urllib.parse.quote(name, safe="")
64
+ payload = _get_json(f"https://pypi.org/pypi/{quoted}/json")
65
+ if payload is None:
66
+ return PackageFacts(name=name, ecosystem="pypi", exists=False)
67
+
68
+ info = payload.get("info") or {}
69
+ releases = payload.get("releases") or {}
70
+
71
+ uploads = sorted(
72
+ file["upload_time_iso_8601"]
73
+ for files in releases.values()
74
+ for file in files
75
+ if file.get("upload_time_iso_8601")
76
+ )
77
+ age = _age_in_days(uploads[0]) if uploads else None
78
+
79
+ project_urls = info.get("project_urls") or {}
80
+ home_page = info.get("home_page") or ""
81
+
82
+ return PackageFacts(
83
+ name=name,
84
+ ecosystem="pypi",
85
+ exists=True,
86
+ age_days=age,
87
+ release_count=sum(1 for files in releases.values() if files),
88
+ has_repo_url=bool(project_urls) or bool(home_page),
89
+ latest_version=info.get("version"),
90
+ summary=info.get("summary") or None,
91
+ )
92
+
93
+
94
+ def fetch_npm(name: str) -> PackageFacts:
95
+ quoted = urllib.parse.quote(name, safe="@/")
96
+ payload = _get_json(f"https://registry.npmjs.org/{quoted}")
97
+ if payload is None:
98
+ return PackageFacts(name=name, ecosystem="npm", exists=False)
99
+
100
+ time_map = payload.get("time") or {}
101
+ created = time_map.get("created")
102
+ age = _age_in_days(created) if created else None
103
+
104
+ versions = payload.get("versions") or {}
105
+ repository = payload.get("repository") or {}
106
+ homepage = payload.get("homepage") or ""
107
+
108
+ return PackageFacts(
109
+ name=name,
110
+ ecosystem="npm",
111
+ exists=True,
112
+ age_days=age,
113
+ release_count=len(versions),
114
+ has_repo_url=bool(repository.get("url")) or bool(homepage),
115
+ latest_version=(payload.get("dist-tags") or {}).get("latest"),
116
+ summary=payload.get("description") or None,
117
+ )
118
+
119
+
120
+ FETCHERS = {"pypi": fetch_pypi, "npm": fetch_npm}
121
+
122
+
123
+ def fetch(name: str, ecosystem: str) -> PackageFacts:
124
+ try:
125
+ fetcher = FETCHERS[ecosystem]
126
+ except KeyError:
127
+ raise ValueError(
128
+ f"unknown ecosystem {ecosystem!r}; expected one of {sorted(FETCHERS)}"
129
+ ) from None
130
+ return fetcher(name)