{"id":7788,"library":"tftpy","title":"tftpy","description":"Tftpy is a pure Python TFTP implementation that includes both client and server classes. It supports RFCs 1350, 2347, 2348, and the tsize option from RFC 2349, with hooks for progress indicators. The current version is 0.8.7, released on February 4, 2026. The project is actively maintained, with regular updates and bug fixes.","status":"active","version":"0.8.7","language":"en","source_language":"en","source_url":"https://github.com/msoulier/tftpy","tags":["tftp","network","file transfer","protocol","client","server"],"install":[{"cmd":"pip install tftpy","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"TftpClient","correct":"import tftpy\nclient = tftpy.TftpClient(...)"},{"symbol":"TftpServer","correct":"import tftpy\nserver = tftpy.TftpServer(...)"}],"quickstart":{"code":"import tftpy\nimport os\nimport threading\nimport time\n\n# --- Server Setup ---\n# Create a temporary directory for the TFTP server root\nserver_root_dir = 'tftp_server_root'\nos.makedirs(server_root_dir, exist_ok=True)\nwith open(os.path.join(server_root_dir, 'testfile.txt'), 'w') as f:\n    f.write('Hello from TFTP server!')\n\ndef start_server():\n    print(f\"Starting TFTP server on 0.0.0.0:6969 with root {server_root_dir}\")\n    server = tftpy.TftpServer(server_root_dir)\n    # Use a non-privileged port for testing\n    try:\n        server.listen('0.0.0.0', 6969, timeout=2)\n    except Exception as e:\n        print(f\"Server error: {e}\")\n    finally:\n        print(\"Server stopped.\")\n        os.remove(os.path.join(server_root_dir, 'testfile.txt'))\n        os.rmdir(server_root_dir)\n\nserver_thread = threading.Thread(target=start_server)\nserver_thread.daemon = True # Allow main program to exit even if server is running\nserver_thread.start()\n\n# Give the server a moment to start\ntime.sleep(1)\n\n# --- Client Usage ---\nprint(\"\\n--- TFTP Client --- \")\nclient = tftpy.TftpClient('127.0.0.1', 6969)\nlocal_download_path = 'downloaded_testfile.txt'\n\ntry:\n    print(f\"Attempting to download 'testfile.txt' to '{local_download_path}'...\")\n    client.download('testfile.txt', local_download_path)\n    if os.path.exists(local_download_path):\n        with open(local_download_path, 'r') as f:\n            content = f.read()\n        print(f\"Download successful! Content: '{content}'\")\n        os.remove(local_download_path)\n    else:\n        print(\"Download failed: file not found locally.\")\nexcept tftpy.TftpException as e:\n    print(f\"TFTP Client Error: {e}\")\nexcept Exception as e:\n    print(f\"An unexpected error occurred: {e}\")\n\nprint(\"Client operations complete.\")\n","lang":"python","description":"This quickstart demonstrates a basic TFTP server listening on a non-privileged port (6969) and a client downloading a file from it. The server creates a temporary root directory and a sample file. The client then connects to localhost and attempts to download this file. The server runs in a separate thread to allow the client to operate."},"warnings":[{"fix":"Upgrade to tftpy version 0.8.0 or later and ensure your Python environment is 3.8+.","message":"Older versions of tftpy (prior to 0.8.0) did not fully support Python 3.x, leading to compatibility issues. Version 0.8.0 introduced Python 3.x support, and current versions require Python >=3.8.","severity":"breaking","affected_versions":"<0.8.0"},{"fix":"Ensure the directory specified for the TFTP server's root exists before instantiating `tftpy.TftpServer` (e.g., `os.makedirs(path, exist_ok=True)`).","message":"When initializing TftpServer, the `root` directory provided must exist and be a valid directory. If it doesn't exist, a `TftpException` will be raised.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Run your server application with appropriate permissions, or use a non-privileged port (e.g., above 1024) for testing and development.","message":"Attempting to bind a TFTP server to the standard TFTP port (69) on most operating systems will require root or administrator privileges. Without these, a permission error (e.g., `OSError: [Errno 13] Permission denied`) will occur.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Update to tftpy 0.8.1 or later to ensure proper logging and security. If you were customising logging with `log.warn`, update to `log.warning`.","message":"In version 0.8.1, the use of `log.warn()` was replaced with `log.warning()` to align with standard Python logging practices, fixing a security issue related to breaking out of the tftproot.","severity":"deprecated","affected_versions":"<0.8.1"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Upgrade your Python environment to 3.8 or newer, and ensure you are using a compatible tftpy version (0.8.0+).","cause":"This error occurs in older Python 3 environments (e.g., 3.4.6) due to changes in string formatting, specifically with bytes and integers when encoding TFTP packets.","error":"TypeError: unsupported operand type(s) for %: 'bytes' and 'int'"},{"fix":"Upgrade to the latest version of tftpy, as significant refactoring and bug fixes have been implemented since version 0.5.0.","cause":"This error has been reported in older versions (e.g., 0.5.0) of tftpy, particularly during file upload operations. It indicates an incompatibility or bug in the state machine for uploads in those specific versions.","error":"AttributeError: 'TftpContextClientUpload' object has no attribute 'sendDAT'"},{"fix":"Check network connectivity and latency. Ensure your TFTP server (if external) is properly configured and responsive. If using an older tftpy client, update to the latest version, as robustness for unreliable networks and buggy clients (including handling of blank OACK options) has been improved in recent versions.","cause":"These messages often indicate network unreliability, packet loss, or an issue with the remote TFTP server's response handling. It can also occur if a TFTP client sends OACK packets with blank or unexpected options, which older tftpy versions might not handle gracefully.","error":"ERROR:tftpy:Received OACK in state ack / WARNING:tftpy:Timeout waiting for traffic, retrying..."},{"fix":"Ensure the directory you intend to serve files from exists and is accessible before initializing `TftpServer`. You can create it programmatically using `os.makedirs(path, exist_ok=True)`.","cause":"The directory path provided to the `tftpy.TftpServer` constructor either does not exist or is not a directory.","error":"tftpy.TftpException: The tftproot must be a directory."}]}