{"id":8473,"library":"pyclamd","title":"pyClamd","description":"pyClamd provides a Pythonic interface to the ClamAV daemon (clamd), allowing applications to scan files and streams for viruses. Currently at version 0.4.0, it offers a robust way to integrate anti-malware scanning into Python projects, with releases occurring as needed for bug fixes or minor enhancements.","status":"active","version":"0.4.0","language":"en","source_language":"en","source_url":"https://github.com/DownWithUp/pyclamd","tags":["security","antivirus","clamav","clamd","malware"],"install":[{"cmd":"pip install pyclamd","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"ClamdAgnostic is the recommended entry point as it attempts both Unix and network socket connections. 'Clamd' is not directly instantiable.","wrong":"from pyclamd import Clamd","symbol":"ClamdAgnostic","correct":"from pyclamd import ClamdAgnostic"},{"symbol":"ClamdNetworkSocket","correct":"from pyclamd import ClamdNetworkSocket"},{"symbol":"ClamdUnixSocket","correct":"from pyclamd import ClamdUnixSocket"}],"quickstart":{"code":"import pyclamd\nimport os\n\n# Ensure Clamd daemon is running and accessible (e.g., via network or Unix socket)\n# For network socket: Host (default '127.0.0.1'), Port (default 3310)\n# For Unix socket: Socket path (default '/var/run/clamav/clamd.ctl')\n\nclamd_host = os.environ.get('CLAMD_HOST', '127.0.0.1')\nclamd_port = int(os.environ.get('CLAMD_PORT', '3310'))\nclamd_socket = os.environ.get('CLAMD_SOCKET', '/var/run/clamav/clamd.ctl') # Default for many Linux systems\n\ntry:\n    # Use ClamdAgnostic for automatic detection (Unix socket preferred if available)\n    # This will try UnixSocket first, then NetworkSocket\n    cd = pyclamd.ClamdAgnostic(\n        unix_socket=clamd_socket,\n        host=clamd_host,\n        port=clamd_port\n    )\n\n    # Ping the ClamAV daemon to check connectivity\n    cd.ping()\n    print(\"Successfully connected to ClamAV daemon.\")\n\n    # EICAR test string (standard antivirus test file)\n    eicar_string = b\"X5O!P%@AP[4\\\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*\"\n    \n    # Scan a stream of bytes\n    result_stream = cd.scan_stream(eicar_string)\n    print(f\"Scan stream result for EICAR: {result_stream}\")\n\n    # Create a dummy file for file scan\n    test_file_path = \"eicar_test.txt\"\n    with open(test_file_path, \"wb\") as f:\n        f.write(eicar_string)\n    \n    result_file = cd.scan_file(test_file_path)\n    print(f\"Scan file result for '{test_file_path}': {result_file}\")\n\n    if os.path.exists(test_file_path):\n        os.remove(test_file_path)\n\nexcept pyclamd.ClamdError as e:\n    print(f\"ClamAV daemon error: {e}\")\n    print(\"Please ensure the ClamAV daemon (clamd) is running and accessible.\")\n    print(f\"  Network: {clamd_host}:{clamd_port}\")\n    print(f\"  Unix Socket: {clamd_socket}\")\nexcept Exception as e:\n    print(f\"An unexpected error occurred: {e}\")","lang":"python","description":"This quickstart demonstrates how to connect to the ClamAV daemon using `ClamdAgnostic`, ping it to verify connectivity, and then scan both a byte stream and a temporary file containing the EICAR test string. It includes basic error handling for common connection issues."},"warnings":[{"fix":"Ensure `clamd` is running as a service on your system. Verify its configuration (network address/port or Unix socket path) matches what `pyclamd` is configured to connect to.","message":"The ClamAV daemon (clamd) must be running and accessible for `pyclamd` to function. `pyclamd` is just a client library and does not start the daemon.","severity":"gotcha","affected_versions":"All"},{"fix":"Always parse the dictionary result. For example, `if result and result.get('path/to/file', ('CLEAN', ''))[0] == 'FOUND':` to check for an infection.","message":"Scan results are dictionaries mapping paths/streams to tuples like `('FOUND', 'Virus.Name')` or `('CLEAN', None)`. They are not simple booleans.","severity":"gotcha","affected_versions":"All"},{"fix":"For explicit connection control, instantiate `pyclamd.ClamdUnixSocket(unix_socket='/path/to/clamd.sock')` or `pyclamd.ClamdNetworkSocket(host='localhost', port=3310)` directly.","message":"`ClamdAgnostic` attempts to connect via Unix socket first, then falls back to a network socket. If both are configured but only one is desired, use `ClamdUnixSocket` or `ClamdNetworkSocket` explicitly.","severity":"gotcha","affected_versions":"All"},{"fix":"Adjust the permissions of the `clamd.ctl` (or similar) socket file, or ensure the Python script is run by a user (e.g., `clamav` or `root`) with appropriate access.","message":"When using Unix sockets, the user running the Python script must have read and write permissions to the ClamAV daemon's socket file.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Start the `clamd` service. Verify the daemon's configuration (`clamd.conf`) for `LocalSocket` or `TCPSocket` settings, and ensure the `pyclamd` client uses matching `host` and `port`.","cause":"The ClamAV daemon (clamd) is either not running or not listening on the specified network host and port.","error":"pyclamd.ClamdError: Could not connect to ClamAV daemon: [Errno 111] Connection refused"},{"fix":"Check the `clamd.conf` for the `LocalSocket` path. Ensure `pyclamd` is configured with the correct `unix_socket` argument (e.g., `ClamdUnixSocket(unix_socket='/var/run/clamav/clamd.ctl')`).","cause":"The specified Unix socket path for `clamd` does not exist or is incorrect.","error":"pyclamd.ClamdError: Could not connect to ClamAV daemon: [Errno 2] No such file or directory"},{"fix":"Grant read/write permissions for the socket file to the user running the script, or run the script as a user (e.g., `clamav`) that already has access. This often involves checking the permissions of `/var/run/clamav/clamd.ctl` and its parent directory.","cause":"The user running the Python script does not have sufficient permissions to access the ClamAV daemon's Unix socket file.","error":"pyclamd.ClamdError: Could not connect to ClamAV daemon: [Errno 13] Permission denied"}]}