Upload Assets to GitHub Release with Python Mock

Simulates uploading binary and text assets to a GitHub release using a mock server, returning structured metadata for each upload.

Easy Python 3.9+ Aug 9, 2026 Git + Python 12 views 0 copies

Python code

53 lines
Python 3.9+
import json
import os
import tempfile
from datetime import datetime

class ReleaseUploader:
    """Simulates uploading assets to a release with a mock server."""
    
    def __init__(self, owner: str, repo: str, tag: str):
        self.owner = owner
        self.repo = repo
        self.tag = tag
        self.uploaded = {}
    
    def mock_upload(self, file_path: str, asset_name: str = None) -> dict:
        """Uploads a file to the mock release and returns the response."""
        if not os.path.isfile(file_path):
            raise FileNotFoundError(f"No such file: {file_path}")
        
        upload_id = f"asset_{len(self.uploaded) + 1:03d}"
        asset_name = asset_name or os.path.basename(file_path)
        size = os.path.getsize(file_path)
        
        response = {
            "url": f"https://mock.example.com/repos/{self.owner}/{self.repo}/releases/{self.tag}/assets/{asset_name}",
            "id": upload_id,
            "name": asset_name,
            "size": size,
            "uploaded_at": datetime.utcnow().isoformat(),
            "state": "uploaded"
        }
        
        self.uploaded[upload_id] = response
        return response

if __name__ == "__main__":
    uploader = ReleaseUploader("octocat", "hello-world", "v1.0.0")
    
    # Simulate uploading two files
    with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f1, \
         tempfile.NamedTemporaryFile(mode='w', suffix='.zip', delete=False) as f2:
        f1.write("Release notes content")
        f2.write("binary content placeholder")
        file1, file2 = f1.name, f2.name
    
    upload1 = uploader.mock_upload(file1, "README.txt")
    upload2 = uploader.mock_upload(file2)
    
    print(json.dumps(list(uploader.uploaded.values()), indent=2))
    
    # Cleanup temp files
    os.unlink(file1)
    os.unlink(file2)

Output

stdout
[
  {
    "url": "https://mock.example.com/repos/octocat/hello-world/releases/v1.0.0/assets/README.txt",
    "id": "asset_001",
    "name": "README.txt",
    "size": 20,
    "uploaded_at": "2024-01-01T12:00:00.000000",
    "state": "uploaded"
  },
  {
    "url": "https://mock.example.com/repos/octocat/hello-world/releases/v1.0.0/assets/tmpabc123.zip",
    "id": "asset_002",
    "name": "tmpabc123.zip",
    "size": 25,
    "uploaded_at": "2024-01-01T12:00:00.000001",
    "state": "uploaded"
  }
]

How it works

The ReleaseUploader class wraps upload logic in a reusable object, storing results in a dictionary keyed by generated upload IDs. mock_upload checks file existence, creates a deterministic URL structure, and records file size via os.path.getsize. Using datetime.utcnow().isoformat() gives a timestamp that mirrors GitHub's API response format. The if __name__ == "__main__" guard keeps the demo isolated from import. This pattern lets you swap the mock body for a real requests.post call later.

Common mistakes

  • Forgetting to close or clean up temp files, leaking disk space
  • Assuming asset_name is optional when you want a stable filename
  • Not handling FileNotFoundError before building the response
  • Using local time instead of UTC for timestamps that match API conventions

Variations

  1. Swap mock_upload for real GitHub API calls with `requests.post` and `Authorization: Bearer` headers
  2. Use `pathlib.Path` to manage file paths and size checks instead of `os` module

Real-world use cases

  • Testing CI/CD pipelines locally that publish build artifacts to GitHub releases.
  • Building a staging script that collects multiple binaries and archives for a versioned release.
  • Writing integration tests against a fake release endpoint so uploads don't hit the live API.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Git + Python

Related tutorials and quizzes for this topic.