{"id":6328,"library":"clamd","title":"Clamd Python Interface","description":"Clamd is a Python interface library for communicating with the ClamAV daemon (`clamd`). It allows Python applications to send files or streams to `clamd` for virus scanning. The current stable version is 1.0.2, with a low release cadence indicating maturity and stability, focusing on Python 3.7+.","status":"active","version":"1.0.2","language":"en","source_language":"en","source_url":"https://github.com/graingert/python-clamd","tags":["antivirus","clamav","security","daemon","virus-scanner"],"install":[{"cmd":"pip install clamd","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"clamd","correct":"import clamd"},{"note":"The primary way to connect using a Unix domain socket.","symbol":"ClamdUnixSocket","correct":"import clamd\ncd = clamd.ClamdUnixSocket()"},{"note":"Used to connect to clamd over TCP/IP.","symbol":"ClamdNetworkSocket","correct":"import clamd\ncd = clamd.ClamdNetworkSocket(host='127.0.0.1', port=3310)"}],"quickstart":{"code":"import clamd\nimport os\n\n# Assuming clamd is running and accessible via its default Unix socket\n# You might need to adjust the socket path or use ClamdNetworkSocket\n# if clamd is running on a network port.\n\ndef scan_string(text_to_scan: str):\n    try:\n        # Common Unix socket paths for clamd:\n        # /var/run/clamav/clamd.ctl (Ubuntu/Debian)\n        # /run/clamd.ctl (Arch Linux)\n        # /var/lib/clamav/clamd.sock\n        \n        # Use environment variable for socket path or default\n        clamd_socket_path = os.environ.get('CLAMD_UNIX_SOCKET', '/var/run/clamav/clamd.ctl')\n        cd = clamd.ClamdUnixSocket(path=clamd_socket_path)\n        \n        # Test connection\n        cd.ping()\n        print(f\"Successfully connected to clamd at {clamd_socket_path}\")\n        \n        # Scan the string. The 'stream' key is arbitrary for stream scans.\n        # 'EICAR_Test_File' is a safe test virus string.\n        result = cd.scan(b'X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*')\n        \n        print(f\"Scan result for string: {result}\")\n        \n        # Interpret result\n        if 'stream' in result and result['stream'][0] == 'FOUND':\n            print(f\"!!! VIRUS DETECTED: {result['stream'][1]} !!!\")\n        elif 'stream' in result and result['stream'][0] == 'OK':\n            print(\"No virus detected.\")\n        else:\n            print(\"Unexpected scan result format.\")\n            \n    except clamd.ClamdError as e:\n        print(f\"Error connecting to or communicating with clamd: {e}\")\n        print(\"Please ensure the clamd daemon is running and accessible at the specified socket path/address, and that your user has permissions.\")\n    except FileNotFoundError:\n        print(f\"Error: Clamd Unix socket not found at {clamd_socket_path}. Please check the path and clamd status.\")\n    except Exception as e:\n        print(f\"An unexpected error occurred: {e}\")\n\nif __name__ == \"__main__\":\n    # Example usage with the EICAR test string\n    scan_string(\"This is a test file for antivirus scanning.\")\n","lang":"python","description":"This quickstart demonstrates how to connect to the ClamAV daemon using a Unix domain socket, send a test string for scanning, and interpret the results. It includes basic error handling for common connection issues."},"warnings":[{"fix":"Ensure the ClamAV daemon (`clamd`) is installed, started, and configured to listen on the specified Unix socket path or network address. Check system logs (e.g., `journalctl -u clamd.service`) for daemon status.","message":"Clamd daemon must be running and accessible. The `clamd` library is merely a client; it does not start or manage the ClamAV daemon. Connection attempts will fail with `clamd.ClamdError` or `FileNotFoundError` if the daemon isn't running or the socket/network address is incorrect.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Adjust file permissions for the clamd socket or ensure the Python process is running as a user or group that has access (e.g., `clamav` group). Alternatively, consider using `ClamdNetworkSocket` if network access is configured and appropriate for your security model.","message":"Unix socket permissions can cause 'Permission denied' errors. When using `ClamdUnixSocket`, the user running the Python script needs appropriate read/write permissions for the socket file (e.g., `/var/run/clamav/clamd.ctl`).","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always check the dictionary structure. For stream scans, the key is typically 'stream'. The value is `('OK', None)` for clean files, or `('FOUND', 'VIRUS_NAME')` if a virus is detected. Example: `result = cd.scan(b'...')`; then access `result['stream'][0]` for status and `result['stream'][1]` for virus name.","message":"The `scan()` and `multiscan()` methods return a dictionary where keys are stream names/file paths and values are tuples `(status, virus_name)`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always provide byte strings (e.g., `b'my data'`) when scanning data directly. If you have a Python string, convert it using `.encode('utf-8')` or another appropriate encoding.","message":"The library primarily uses bytes for scanning inputs, not strings. While Python 3 handles string-to-bytes implicitly in some I/O operations, explicitly encoding input strings to bytes (`my_string.encode()`) is best practice.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z"}