Repository: whitphx/transformers.js.py (language: python)

Issue:
Make the import name same as the PyPI package name



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index aa4628d..c619891 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ let out = await pipe('I love transformers!');
 <td>
 
 ```python
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 
 transformers = await import_transformers_js()
 pipeline = transformers.pipeline
@@ -64,7 +64,7 @@ See the [Transformers.js document](https://github.com/xenova/transformers.js/) f
 ```python
 %pip install transformers_js_py
 
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 
 transformers = await import_transformers_js()
 pipeline = transformers.pipeline
@@ -85,7 +85,7 @@ print(out)
 ```python
 import streamlit as st
 
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 
 st.title("Sentiment analysis")
 
@@ -137,7 +137,7 @@ transformers_js_py
 
 <gradio-file name="app.py" entrypoint>
 import gradio as gr
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 
 transformers = await import_transformers_js()
 pipeline = transformers.pipeline
@@ -169,7 +169,7 @@ For more details about Gradio-lite, please read [Gradio-Lite: Serverless Gradio
 
 ```python
 from shiny import App, render, ui
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 
 app_ui = ui.page_fluid(
     ui.input_text("text", "Text input", placeholder="Enter text"),
@@ -218,7 +218,7 @@ app = App(app_ui, server, debug=True)
     </py-config>
     <py-script>
         import asyncio
-        from transformers_js import import_transformers_js
+        from transformers_js_py import import_transformers_js
 
         text_input = Element("text-input")
 
@@ -252,7 +252,7 @@ With [HoloViz Panel](https://panel.holoviz.org) you develop your app on your lap
 Install the requirements
 
 ```bash
-pip install panel transformers_js_py 
+pip install panel transformers_js_py
 ```
 
 Create the **app.py** file in your favorite editor or IDE.
@@ -264,7 +264,7 @@ pn.extension(sizing_mode="stretch_width", design="material")
 
 @pn.cache
 async def _get_pipeline(model="sentiment-analysis"):
-    from transformers_js import import_transformers_js
+    from transformers_js_py import import_transformers_js
     transformers = await import_transformers_js()
     return await transformers.pipeline(model)
 
@@ -315,7 +315,7 @@ pn.extension(design="material")
 
 @pn.cache
 async def _get_pipeline(model):
-    from transformers_js import import_transformers_js
+    from transformers_js_py import import_transformers_js
     transformers = await import_transformers_js()
     return await transformers.pipeline(model)
 
diff --git a/pyproject.toml b/pyproject.toml
index ab2ec8a..18c3683 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -5,7 +5,10 @@ description = ""
 authors = ["Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com>"]
 license = "Apache-2.0"
 readme = "README.md"
-packages = [{include = "transformers_js"}]
+packages = [
+    {include = "transformers_js_py"},
+    {include = "transformers_js"},
+]
 repository = "https://github.com/whitphx/transformers.js.py"
 
 [tool.poetry.dependencies]
diff --git a/transformers_js/__init__.py b/transformers_js/__init__.py
index f51265e..3fadbdb 100644
--- a/transformers_js/__init__.py
+++ b/transformers_js/__init__.py
@@ -1,97 +1,7 @@
-from typing import Any
+"""
+This module was created as an alias for `transformers_js_py`
+due to a historical reason that the original package name was `transformers_js`.
+Ref: https://github.com/whitphx/transformers.js.py/issues/26
+"""
 
-import js
-import pyodide.code
-import pyodide.ffi
-import pyodide.webloop
-
-from .url import as_url
-
-
-class TjsModuleProxy:
-    def __init__(self, js_obj: pyodide.ffi.JsProxy):
-        if not isinstance(js_obj, pyodide.ffi.JsProxy) or js_obj.typeof != "object":
-            raise TypeError("js_obj must be a JS module object")
-        self.js_obj = js_obj
-
-    def __getattr__(self, name: str) -> Any:
-        res = getattr(self.js_obj, name)
-        if isinstance(res, pyodide.ffi.JsProxy):
-            return TjsProxy(res)
-        return res
-
-    def __repr__(self) -> str:
-        return "TjsModuleProxy({})".format(", ".join(self.js_obj.object_keys()))
-
-
-class TjsProxy:
-    def __init__(self, js_obj: pyodide.ffi.JsProxy):
-        self._js_obj = js_obj
-
-    def __call__(self, *args: Any, **kwds: Any) -> Any:
-        if hasattr(self._js_obj, "_call"):
-            args = pyodide.ffi.to_js(args)
-            kwds = pyodide.ffi.to_js(kwds)
-
-            # Transformers.js uses a custom _call() method
-            # to make the JS classes callable.
-            # https://github.com/xenova/transformers.js/blob/2.4.1/src/utils/core.js#L45-L77
-            res = self._js_obj._call(*args, **kwds)
-        else:
-            res = self._js_obj(*args, **kwds)
-
-        return wrap_or_unwrap_proxy_object(res)
-
-    def __getattr__(self, name: str) -> Any:
-        res = getattr(self._js_obj, name)
-        return wrap_or_unwrap_proxy_object(res)
-
-    def __getitem__(self, key: Any) -> Any:
-        res = self._js_obj[key]
-        return wrap_or_unwrap_proxy_object(res)
-
-    def __setitem__(self, key: Any, value: Any) -> None:
-        self._js_obj[key] = value
-
-    def __setattr__(self, __name: str, __value: Any) -> None:
-        if __name == "_js_obj":
-            super().__setattr__("_js_obj", __value)
-        else:
-            setattr(self._js_obj, __name, __value)
-
-
-def wrap_or_unwrap_proxy_object(obj):
-    if isinstance(obj, pyodide.ffi.JsProxy):
-        if obj.typeof == "object":
-            return obj.to_py()
-        return TjsProxy(obj)
-    elif isinstance(obj, pyodide.webloop.PyodideFuture):
-        return obj.then(wrap_or_unwrap_proxy_object)
-    return obj
-
-
-async def import_transformers_js(version: str = "latest"):
-    pyodide.code.run_js(
-        """
-    async function loadTransformersJs(version) {
-        const isBrowserMainThread = typeof window !== 'undefined';
-        const isWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
-        const isBrowser = isBrowserMainThread || isWorker;
-        const transformers = await import(isBrowser ? 'https://cdn.jsdelivr.net/npm/@xenova/transformers@' + version : '@xenova/transformers');
-
-        transformers.env.allowLocalModels = false;
-
-        globalThis._transformers = {  // Convert a module to an object.
-            ...transformers,
-        };
-    }
-    """  # noqa: E501
-    )
-    loadTransformersJsFn = js.loadTransformersJs
-    await loadTransformersJsFn(version)
-
-    transformers = js._transformers
-    return TjsModuleProxy(transformers)
-
-
-__all__ = ["as_url", "import_transformers_js"]
+from transformers_js_py import *  # noqa: F401, F403
diff --git a/transformers_js_py/__init__.py b/transformers_js_py/__init__.py
new file mode 100644
index 0000000..f51265e
--- /dev/null
+++ b/transformers_js_py/__init__.py
@@ -0,0 +1,97 @@
+from typing import Any
+
+import js
+import pyodide.code
+import pyodide.ffi
+import pyodide.webloop
+
+from .url import as_url
+
+
+class TjsModuleProxy:
+    def __init__(self, js_obj: pyodide.ffi.JsProxy):
+        if not isinstance(js_obj, pyodide.ffi.JsProxy) or js_obj.typeof != "object":
+            raise TypeError("js_obj must be a JS module object")
+        self.js_obj = js_obj
+
+    def __getattr__(self, name: str) -> Any:
+        res = getattr(self.js_obj, name)
+        if isinstance(res, pyodide.ffi.JsProxy):
+            return TjsProxy(res)
+        return res
+
+    def __repr__(self) -> str:
+        return "TjsModuleProxy({})".format(", ".join(self.js_obj.object_keys()))
+
+
+class TjsProxy:
+    def __init__(self, js_obj: pyodide.ffi.JsProxy):
+        self._js_obj = js_obj
+
+    def __call__(self, *args: Any, **kwds: Any) -> Any:
+        if hasattr(self._js_obj, "_call"):
+            args = pyodide.ffi.to_js(args)
+            kwds = pyodide.ffi.to_js(kwds)
+
+            # Transformers.js uses a custom _call() method
+            # to make the JS classes callable.
+            # https://github.com/xenova/transformers.js/blob/2.4.1/src/utils/core.js#L45-L77
+            res = self._js_obj._call(*args, **kwds)
+        else:
+            res = self._js_obj(*args, **kwds)
+
+        return wrap_or_unwrap_proxy_object(res)
+
+    def __getattr__(self, name: str) -> Any:
+        res = getattr(self._js_obj, name)
+        return wrap_or_unwrap_proxy_object(res)
+
+    def __getitem__(self, key: Any) -> Any:
+        res = self._js_obj[key]
+        return wrap_or_unwrap_proxy_object(res)
+
+    def __setitem__(self, key: Any, value: Any) -> None:
+        self._js_obj[key] = value
+
+    def __setattr__(self, __name: str, __value: Any) -> None:
+        if __name == "_js_obj":
+            super().__setattr__("_js_obj", __value)
+        else:
+            setattr(self._js_obj, __name, __value)
+
+
+def wrap_or_unwrap_proxy_object(obj):
+    if isinstance(obj, pyodide.ffi.JsProxy):
+        if obj.typeof == "object":
+            return obj.to_py()
+        return TjsProxy(obj)
+    elif isinstance(obj, pyodide.webloop.PyodideFuture):
+        return obj.then(wrap_or_unwrap_proxy_object)
+    return obj
+
+
+async def import_transformers_js(version: str = "latest"):
+    pyodide.code.run_js(
+        """
+    async function loadTransformersJs(version) {
+        const isBrowserMainThread = typeof window !== 'undefined';
+        const isWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
+        const isBrowser = isBrowserMainThread || isWorker;
+        const transformers = await import(isBrowser ? 'https://cdn.jsdelivr.net/npm/@xenova/transformers@' + version : '@xenova/transformers');
+
+        transformers.env.allowLocalModels = false;
+
+        globalThis._transformers = {  // Convert a module to an object.
+            ...transformers,
+        };
+    }
+    """  # noqa: E501
+    )
+    loadTransformersJsFn = js.loadTransformersJs
+    await loadTransformersJsFn(version)
+
+    transformers = js._transformers
+    return TjsModuleProxy(transformers)
+
+
+__all__ = ["as_url", "import_transformers_js"]
diff --git a/transformers_js/url.py b/transformers_js_py/url.py
similarity index 100%
rename from transformers_js/url.py
rename to transformers_js_py/url.py


Test patch:
diff --git a/pyodide-e2e/package.json b/pyodide-e2e/package.json
index f7fc1b1..455a579 100644
--- a/pyodide-e2e/package.json
+++ b/pyodide-e2e/package.json
@@ -6,7 +6,7 @@
   "scripts": {
     "dev": "run-p dev:*",
     "dev:front": "vite",
-    "dev:python": "chokidar \"../transformers_js/**/*.py\" --initial -c \"cd .. && poetry build\"",
+    "dev:python": "chokidar \"../transformers_js_py/**/*.py\" \"../transformers_js/**/*.py\" --initial -c \"cd .. && poetry build\"",
     "build": "tsc && vite build",
     "preview": "vite preview",
     "test": "vitest"
diff --git a/pyodide-e2e/src/main.ts b/pyodide-e2e/src/main.ts
index b9b31df..63cfae5 100644
--- a/pyodide-e2e/src/main.ts
+++ b/pyodide-e2e/src/main.ts
@@ -12,7 +12,7 @@ async function main() {
   await micropip.install(wheelUrl);
 
   await pyodide.runPythonAsync(`
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 transformers = await import_transformers_js()
 
 pipeline = transformers.pipeline
diff --git a/pyodide-e2e/src/tests/pipeline.test.ts b/pyodide-e2e/src/tests/pipeline.test.ts
index 6cce69f..acf3b6d 100644
--- a/pyodide-e2e/src/tests/pipeline.test.ts
+++ b/pyodide-e2e/src/tests/pipeline.test.ts
@@ -20,7 +20,7 @@ suite("transformers.pipeline", () => {
       });
 
     await pyodide.runPythonAsync(`
-from transformers_js import import_transformers_js, as_url
+from transformers_js_py import import_transformers_js, as_url
 
 transformers = await import_transformers_js()
 pipeline = transformers.pipeline
diff --git a/pyodide-e2e/src/tests/utils.ts b/pyodide-e2e/src/tests/utils.ts
index d86907a..50be3a9 100644
--- a/pyodide-e2e/src/tests/utils.ts
+++ b/pyodide-e2e/src/tests/utils.ts
@@ -26,7 +26,7 @@ export async function setupPyodideForTest(): Promise<PyodideInterface> {
   }
 
   await pyodide.runPythonAsync(`
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 transformers = await import_transformers_js()
   `)
 
diff --git a/pyodide-e2e/src/worker.ts b/pyodide-e2e/src/worker.ts
index 1c09153..4f6a04b 100644
--- a/pyodide-e2e/src/worker.ts
+++ b/pyodide-e2e/src/worker.ts
@@ -16,7 +16,7 @@ async function main() {
   await micropip.install(wheelUrl);
 
   await pyodide.runPythonAsync(`
-from transformers_js import import_transformers_js
+from transformers_js_py import import_transformers_js
 transformers = await import_transformers_js()
 
 pipeline = transformers.pipeline