phasermagic


Namephasermagic JSON
Version 1.2.3 PyPI version JSON
download
home_pageNone
SummaryThis Python package is a magic command that executes Python code in code cells on Jupyter and Google Colab using PyScript and Phaser within an iframe.
upload_time2024-12-31 21:55:40
maintainerNone
docs_urlNone
authorUniras
requires_pythonNone
licenseMIT License
keywords phaser jupyter magic colab iframe pyscript
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Phaser Magic Command

## 概要

Jypyter(notebook/lab)・VSCodeまたはGoogle ColabでPhaserを使ったコードセルのPythonコードをPyScriptを使ってiframe(ブラウザ)上で実行するマジックコマンドです。

## 使い方

### マジックコマンドの追加

コードセルに以下のコードを貼り付けて実行しマジックコマンドを登録してください。カーネルやランタイムを再起動する度に再実行する必要があります。

```python
%pip install -q -U pysmagic phasermagic
from phasermagic import register_phasermagic

register_phasermagic()
```

### マジックコマンドの使い方

コードセルの冒頭に以下のようにマジックコマンドを記述してください。実行するとアウトプットにiframeが表示されてその中でコードセルのコードがPyScriptで実行されます。

以下は、Phaserライブラリを使って描画した赤い円を矢印キーで動かす例です。

Phaser関連クラスに辞書形式のオプションを渡す場合は、gameconfig関数を通じて渡す必要があります。(gamestart関数に渡すconfig変数は内部でgameconfig関数を使っているので使う必要はありません)

また、PyodideでPhaser関連クラスにコールバック関数を渡す場合は、Pyodide.ffi.create_proxy関数を通じて渡す必要があります。(MicroPythonではそのまま関数を渡しても大丈夫です)

```python
%%runphaser 500 500 white

# from pyodide.ffi import create_proxy

scene = None
cursor = None
graphics = None
x = 100
y = 100

def create(data):
  global cursor, graphics
  cursor = scene.input.keyboard.createCursorKeys()
  graphics = scene.add.graphics(gameconfig({'fillStyle': {'color': 0xff0000}}))


def update(time, delta):
  global x, y
  graphics.clear()
  if cursor.left.isDown:
    x -= 5
  if cursor.right.isDown:
    x += 5
  if cursor.up.isDown:
    y -= 5
  if cursor.down.isDown:
    y += 5
  graphics.fillCircle(x, y, 30)


scene = Phaser.Scene.new('SampleScene')
scene.create = create  # scene.create = create_proxy(create)
scene.update = update  # scene.update = create_proxy(update)

config = {
  'type': Phaser.AUTO,
  'width': 300,
  'height': 300,
  'scene': [scene]
}

game = gamestart(config)
```

Phaser.SceneクラスをPyScript用にラップしたPhaserSceneクラスを継承して独自のシーンクラスを作成する形でも記述できます。

PhaserSceneクラス内でcreate_proxy関数を通じたコールバックの設定をしているので、PyodideでもPhaserSceneクラスを継承する場合はcreate_proxy関数を使う必要はありません。

PhaserSceneクラスのインスタンスをconfigのsceneに設定する場合はインスタンスのsceneプロパティを渡す必要がありますが(例:`scene: [Scene1().scene]`)、

scenes関数を使ってPhaserSceneインスタンスを直接設定することもできます(例:`'scene': scenes(Scene1())`)。`,`で区切って複数渡すこともできます(例:`'scene': scenes(Scene1(), Scene2())`)。

```python
%%runphaser 500 500 white

class SampleScene(PhaserScene):
    def __init__(self):
        super().__init__('SampleScene')
        self.cursor = None
        self.graphics = None
        self.x = 100
        self.y = 100

    def create(self, this, data):
        self.cursor = this.input.keyboard.createCursorKeys()
        self.graphics = this.add.graphics(gameconfig({'fillStyle': {'color': 0xff0000}}))

    def update(self, this, time, delta):
        self.graphics.clear()
        if self.cursor.left.isDown:
            self.x -= 5
        if self.cursor.right.isDown:
            self.x += 5
        if self.cursor.up.isDown:
            self.y -= 5
        if self.cursor.down.isDown:
            self.y += 5
        self.graphics.fillCircle(self.x, self.y, 30)


config = {
    'type': Phaser.AUTO,
    'width': 300,
    'height': 300,
    'scene': scenes(SampleScene())
}

game = gamestart(config)
```

### グローバル変数

PyScriptから以下の変数にアクセスできます。

- 別のセルで設定したグローバル変数(_で始まる変数名やJSONに変換できないものは除く)
- マジックコマンドの引数py_valで設定した変数
- width: iframeの幅(マジックコマンドの引数で指定した幅)
- height: iframeの高さ(マジックコマンドの引数で指定した高さ)

この変数はjs.pysオブジェクトを介してアクセスできます。
変数名が衝突した場合は上記リストの順に上書きされて適用されます。

### マジックコマンド

#### %%runphaser

コードセルのコードをPyScriptを使ってiframe内で実行します。

```jupyter
%%runphaser [width] [height] [background] [py_type] [py_val] [py_conf] [js_src] [py_ver]
```

- width: iframeの幅を指定します。デフォルトは500です。
- height: iframeの高さを指定します。デフォルトは500です。
- background: iframeの背景色を指定します。デフォルトはwhiteです。
- py_type: 実行するPythonの種類。pyまたはmpyを指定します。pyは CPython互換のPyodide、mpyはMicroPytonで実行します。デフォルトはmpyです。
- py_val: PyScriptに渡すデータを''で囲んだJSON文字列形式で設定します。デフォルトは'{}'です
- py_conf: PyScriptの設定を''で囲んだJSON文字列形式で指定します。デフォルトは'{}'です。
- js_src: 外部JavaScriptのURLを''で囲んだ文字列のJSON配列形式で指定します。デフォルトは'[]'です。
- py_ver: PyScriptのバージョンを指定します、Noneを指定するとモジュール内部で設定したデフォルトのバージョンを使用します。デフォルトはNoneです。

#### %%genphaser

セル内のPythonコードをPyScriptを用いてiframe内で実行するために生成したHTMLを表示するマジックコマンド

引数は%%runphaserと同じです。

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "phasermagic",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "Phaser, jupyter, magic, colab, iframe, pyscript",
    "author": "Uniras",
    "author_email": "tkappeng@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/14/8b/62a1e0d57c501471e7c64c920a2988a2a2a84932d36d46f9a1d4806c39df/phasermagic-1.2.3.tar.gz",
    "platform": null,
    "description": "# Phaser Magic Command\r\n\r\n## \u6982\u8981\r\n\r\nJypyter(notebook/lab)\u30fbVSCode\u307e\u305f\u306fGoogle Colab\u3067Phaser\u3092\u4f7f\u3063\u305f\u30b3\u30fc\u30c9\u30bb\u30eb\u306ePython\u30b3\u30fc\u30c9\u3092PyScript\u3092\u4f7f\u3063\u3066iframe(\u30d6\u30e9\u30a6\u30b6)\u4e0a\u3067\u5b9f\u884c\u3059\u308b\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u3067\u3059\u3002\r\n\r\n## \u4f7f\u3044\u65b9\r\n\r\n### \u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u306e\u8ffd\u52a0\r\n\r\n\u30b3\u30fc\u30c9\u30bb\u30eb\u306b\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u5b9f\u884c\u3057\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u3092\u767b\u9332\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30ab\u30fc\u30cd\u30eb\u3084\u30e9\u30f3\u30bf\u30a4\u30e0\u3092\u518d\u8d77\u52d5\u3059\u308b\u5ea6\u306b\u518d\u5b9f\u884c\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002\r\n\r\n```python\r\n%pip install -q -U pysmagic phasermagic\r\nfrom phasermagic import register_phasermagic\r\n\r\nregister_phasermagic()\r\n```\r\n\r\n### \u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u306e\u4f7f\u3044\u65b9\r\n\r\n\u30b3\u30fc\u30c9\u30bb\u30eb\u306e\u5192\u982d\u306b\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u3092\u8a18\u8ff0\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u5b9f\u884c\u3059\u308b\u3068\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u306biframe\u304c\u8868\u793a\u3055\u308c\u3066\u305d\u306e\u4e2d\u3067\u30b3\u30fc\u30c9\u30bb\u30eb\u306e\u30b3\u30fc\u30c9\u304cPyScript\u3067\u5b9f\u884c\u3055\u308c\u307e\u3059\u3002\r\n\r\n\u4ee5\u4e0b\u306f\u3001Phaser\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f7f\u3063\u3066\u63cf\u753b\u3057\u305f\u8d64\u3044\u5186\u3092\u77e2\u5370\u30ad\u30fc\u3067\u52d5\u304b\u3059\u4f8b\u3067\u3059\u3002\r\n\r\nPhaser\u95a2\u9023\u30af\u30e9\u30b9\u306b\u8f9e\u66f8\u5f62\u5f0f\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u6e21\u3059\u5834\u5408\u306f\u3001gameconfig\u95a2\u6570\u3092\u901a\u3058\u3066\u6e21\u3059\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002(gamestart\u95a2\u6570\u306b\u6e21\u3059config\u5909\u6570\u306f\u5185\u90e8\u3067gameconfig\u95a2\u6570\u3092\u4f7f\u3063\u3066\u3044\u308b\u306e\u3067\u4f7f\u3046\u5fc5\u8981\u306f\u3042\u308a\u307e\u305b\u3093)\r\n\r\n\u307e\u305f\u3001Pyodide\u3067Phaser\u95a2\u9023\u30af\u30e9\u30b9\u306b\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u95a2\u6570\u3092\u6e21\u3059\u5834\u5408\u306f\u3001Pyodide.ffi.create_proxy\u95a2\u6570\u3092\u901a\u3058\u3066\u6e21\u3059\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002(MicroPython\u3067\u306f\u305d\u306e\u307e\u307e\u95a2\u6570\u3092\u6e21\u3057\u3066\u3082\u5927\u4e08\u592b\u3067\u3059)\r\n\r\n```python\r\n%%runphaser 500 500 white\r\n\r\n# from pyodide.ffi import create_proxy\r\n\r\nscene = None\r\ncursor = None\r\ngraphics = None\r\nx = 100\r\ny = 100\r\n\r\ndef create(data):\r\n  global cursor, graphics\r\n  cursor = scene.input.keyboard.createCursorKeys()\r\n  graphics = scene.add.graphics(gameconfig({'fillStyle': {'color': 0xff0000}}))\r\n\r\n\r\ndef update(time, delta):\r\n  global x, y\r\n  graphics.clear()\r\n  if cursor.left.isDown:\r\n    x -= 5\r\n  if cursor.right.isDown:\r\n    x += 5\r\n  if cursor.up.isDown:\r\n    y -= 5\r\n  if cursor.down.isDown:\r\n    y += 5\r\n  graphics.fillCircle(x, y, 30)\r\n\r\n\r\nscene = Phaser.Scene.new('SampleScene')\r\nscene.create = create  # scene.create = create_proxy(create)\r\nscene.update = update  # scene.update = create_proxy(update)\r\n\r\nconfig = {\r\n  'type': Phaser.AUTO,\r\n  'width': 300,\r\n  'height': 300,\r\n  'scene': [scene]\r\n}\r\n\r\ngame = gamestart(config)\r\n```\r\n\r\nPhaser.Scene\u30af\u30e9\u30b9\u3092PyScript\u7528\u306b\u30e9\u30c3\u30d7\u3057\u305fPhaserScene\u30af\u30e9\u30b9\u3092\u7d99\u627f\u3057\u3066\u72ec\u81ea\u306e\u30b7\u30fc\u30f3\u30af\u30e9\u30b9\u3092\u4f5c\u6210\u3059\u308b\u5f62\u3067\u3082\u8a18\u8ff0\u3067\u304d\u307e\u3059\u3002\r\n\r\nPhaserScene\u30af\u30e9\u30b9\u5185\u3067create_proxy\u95a2\u6570\u3092\u901a\u3058\u305f\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u306e\u8a2d\u5b9a\u3092\u3057\u3066\u3044\u308b\u306e\u3067\u3001Pyodide\u3067\u3082PhaserScene\u30af\u30e9\u30b9\u3092\u7d99\u627f\u3059\u308b\u5834\u5408\u306fcreate_proxy\u95a2\u6570\u3092\u4f7f\u3046\u5fc5\u8981\u306f\u3042\u308a\u307e\u305b\u3093\u3002\r\n\r\nPhaserScene\u30af\u30e9\u30b9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092config\u306escene\u306b\u8a2d\u5b9a\u3059\u308b\u5834\u5408\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306escene\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u6e21\u3059\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u304c(\u4f8b:`scene: [Scene1().scene]`)\u3001\r\n\r\nscenes\u95a2\u6570\u3092\u4f7f\u3063\u3066PhaserScene\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u76f4\u63a5\u8a2d\u5b9a\u3059\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059(\u4f8b:`'scene': scenes(Scene1())`)\u3002`,`\u3067\u533a\u5207\u3063\u3066\u8907\u6570\u6e21\u3059\u3053\u3068\u3082\u3067\u304d\u307e\u3059(\u4f8b:`'scene': scenes(Scene1(), Scene2())`)\u3002\r\n\r\n```python\r\n%%runphaser 500 500 white\r\n\r\nclass SampleScene(PhaserScene):\r\n    def __init__(self):\r\n        super().__init__('SampleScene')\r\n        self.cursor = None\r\n        self.graphics = None\r\n        self.x = 100\r\n        self.y = 100\r\n\r\n    def create(self, this, data):\r\n        self.cursor = this.input.keyboard.createCursorKeys()\r\n        self.graphics = this.add.graphics(gameconfig({'fillStyle': {'color': 0xff0000}}))\r\n\r\n    def update(self, this, time, delta):\r\n        self.graphics.clear()\r\n        if self.cursor.left.isDown:\r\n            self.x -= 5\r\n        if self.cursor.right.isDown:\r\n            self.x += 5\r\n        if self.cursor.up.isDown:\r\n            self.y -= 5\r\n        if self.cursor.down.isDown:\r\n            self.y += 5\r\n        self.graphics.fillCircle(self.x, self.y, 30)\r\n\r\n\r\nconfig = {\r\n    'type': Phaser.AUTO,\r\n    'width': 300,\r\n    'height': 300,\r\n    'scene': scenes(SampleScene())\r\n}\r\n\r\ngame = gamestart(config)\r\n```\r\n\r\n### \u30b0\u30ed\u30fc\u30d0\u30eb\u5909\u6570\r\n\r\nPyScript\u304b\u3089\u4ee5\u4e0b\u306e\u5909\u6570\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002\r\n\r\n- \u5225\u306e\u30bb\u30eb\u3067\u8a2d\u5b9a\u3057\u305f\u30b0\u30ed\u30fc\u30d0\u30eb\u5909\u6570(_\u3067\u59cb\u307e\u308b\u5909\u6570\u540d\u3084JSON\u306b\u5909\u63db\u3067\u304d\u306a\u3044\u3082\u306e\u306f\u9664\u304f)\r\n- \u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u306e\u5f15\u6570py_val\u3067\u8a2d\u5b9a\u3057\u305f\u5909\u6570\r\n- width: iframe\u306e\u5e45(\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u306e\u5f15\u6570\u3067\u6307\u5b9a\u3057\u305f\u5e45)\r\n- height: iframe\u306e\u9ad8\u3055(\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\u306e\u5f15\u6570\u3067\u6307\u5b9a\u3057\u305f\u9ad8\u3055)\r\n\r\n\u3053\u306e\u5909\u6570\u306fjs.pys\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u4ecb\u3057\u3066\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002\r\n\u5909\u6570\u540d\u304c\u885d\u7a81\u3057\u305f\u5834\u5408\u306f\u4e0a\u8a18\u30ea\u30b9\u30c8\u306e\u9806\u306b\u4e0a\u66f8\u304d\u3055\u308c\u3066\u9069\u7528\u3055\u308c\u307e\u3059\u3002\r\n\r\n### \u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\r\n\r\n#### %%runphaser\r\n\r\n\u30b3\u30fc\u30c9\u30bb\u30eb\u306e\u30b3\u30fc\u30c9\u3092PyScript\u3092\u4f7f\u3063\u3066iframe\u5185\u3067\u5b9f\u884c\u3057\u307e\u3059\u3002\r\n\r\n```jupyter\r\n%%runphaser [width] [height] [background] [py_type] [py_val] [py_conf] [js_src] [py_ver]\r\n```\r\n\r\n- width: iframe\u306e\u5e45\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306f500\u3067\u3059\u3002\r\n- height: iframe\u306e\u9ad8\u3055\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306f500\u3067\u3059\u3002\r\n- background: iframe\u306e\u80cc\u666f\u8272\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306fwhite\u3067\u3059\u3002\r\n- py_type: \u5b9f\u884c\u3059\u308bPython\u306e\u7a2e\u985e\u3002py\u307e\u305f\u306fmpy\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002py\u306f CPython\u4e92\u63db\u306ePyodide\u3001mpy\u306fMicroPyton\u3067\u5b9f\u884c\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306fmpy\u3067\u3059\u3002\r\n- py_val: PyScript\u306b\u6e21\u3059\u30c7\u30fc\u30bf\u3092''\u3067\u56f2\u3093\u3060JSON\u6587\u5b57\u5217\u5f62\u5f0f\u3067\u8a2d\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306f'{}'\u3067\u3059\r\n- py_conf: PyScript\u306e\u8a2d\u5b9a\u3092''\u3067\u56f2\u3093\u3060JSON\u6587\u5b57\u5217\u5f62\u5f0f\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306f'{}'\u3067\u3059\u3002\r\n- js_src: \u5916\u90e8JavaScript\u306eURL\u3092''\u3067\u56f2\u3093\u3060\u6587\u5b57\u5217\u306eJSON\u914d\u5217\u5f62\u5f0f\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306f'[]'\u3067\u3059\u3002\r\n- py_ver: PyScript\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u6307\u5b9a\u3057\u307e\u3059\u3001None\u3092\u6307\u5b9a\u3059\u308b\u3068\u30e2\u30b8\u30e5\u30fc\u30eb\u5185\u90e8\u3067\u8a2d\u5b9a\u3057\u305f\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u4f7f\u7528\u3057\u307e\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u306fNone\u3067\u3059\u3002\r\n\r\n#### %%genphaser\r\n\r\n\u30bb\u30eb\u5185\u306ePython\u30b3\u30fc\u30c9\u3092PyScript\u3092\u7528\u3044\u3066iframe\u5185\u3067\u5b9f\u884c\u3059\u308b\u305f\u3081\u306b\u751f\u6210\u3057\u305fHTML\u3092\u8868\u793a\u3059\u308b\u30de\u30b8\u30c3\u30af\u30b3\u30de\u30f3\u30c9\r\n\r\n\u5f15\u6570\u306f%%runphaser\u3068\u540c\u3058\u3067\u3059\u3002\r\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "This Python package is a magic command that executes Python code in code cells on Jupyter and Google Colab using PyScript and Phaser within an iframe.",
    "version": "1.2.3",
    "project_urls": {
        "Homepage": "https://github.com/uniras/PhaserMagic",
        "Repository": "https://github.com/uniras/PhaserMagic"
    },
    "split_keywords": [
        "phaser",
        " jupyter",
        " magic",
        " colab",
        " iframe",
        " pyscript"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "cd8f806eb1ba28a06b4e9cfc66b4934472ba4ed7fd4ffeb35425c5f83611f140",
                "md5": "edb7a41d7df782055fc9294d45331cc6",
                "sha256": "668ab9288777ccbcdf1e45113b5c239f8fd0131ac02e66b588803c10371b34ea"
            },
            "downloads": -1,
            "filename": "phasermagic-1.2.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "edb7a41d7df782055fc9294d45331cc6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 5966,
            "upload_time": "2024-12-31T21:55:36",
            "upload_time_iso_8601": "2024-12-31T21:55:36.291619Z",
            "url": "https://files.pythonhosted.org/packages/cd/8f/806eb1ba28a06b4e9cfc66b4934472ba4ed7fd4ffeb35425c5f83611f140/phasermagic-1.2.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "148b62a1e0d57c501471e7c64c920a2988a2a2a84932d36d46f9a1d4806c39df",
                "md5": "f08ed6071a7c5bb8111f99b9744d37cd",
                "sha256": "628e00b1708d44ddd15226e2855cab846d467efeb80879b30474373ec0441bdb"
            },
            "downloads": -1,
            "filename": "phasermagic-1.2.3.tar.gz",
            "has_sig": false,
            "md5_digest": "f08ed6071a7c5bb8111f99b9744d37cd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 5443,
            "upload_time": "2024-12-31T21:55:40",
            "upload_time_iso_8601": "2024-12-31T21:55:40.414695Z",
            "url": "https://files.pythonhosted.org/packages/14/8b/62a1e0d57c501471e7c64c920a2988a2a2a84932d36d46f9a1d4806c39df/phasermagic-1.2.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-31 21:55:40",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "uniras",
    "github_project": "PhaserMagic",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "phasermagic"
}
        
Elapsed time: 0.46074s