Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/deps/actions-311-minimum_versions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ dependencies:
- pyarrow=12.0.1
- pyiceberg=0.7.1
- pymysql=1.1.0
- pyqt=5.15.9
- pyreadstat=1.2.6
- pytables=3.8.0
- python-calamine=0.1.7
Expand All @@ -62,4 +61,5 @@ dependencies:
- zstandard=0.22.0

- pip:
- PyQt6==6.7.1
- tzdata==2023.3
2 changes: 1 addition & 1 deletion ci/deps/actions-311.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ dependencies:
- numexpr>=2.9.0
- odfpy>=1.4.1
- qtpy>=2.3.0
- pyqt>=5.15.9
- openpyxl>=3.1.2
- psycopg2>=2.9.9
- pyarrow>=12.0.1
Expand All @@ -60,4 +59,5 @@ dependencies:
- zstandard>=0.22.0

- pip:
- PyQt6>=6.7.1
- tzdata>=2023.3
2 changes: 1 addition & 1 deletion ci/deps/actions-312.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ dependencies:
- numexpr>=2.9.0
- odfpy>=1.4.1
- qtpy>=2.3.0
- pyqt>=5.15.9
- openpyxl>=3.1.2
- psycopg2>=2.9.9
- pyarrow>=12.0.1
Expand All @@ -60,4 +59,5 @@ dependencies:
- zstandard>=0.22.0

- pip:
- PyQt6>=6.7.1
- tzdata>=2023.3
2 changes: 1 addition & 1 deletion ci/deps/actions-313-downstream_compat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ dependencies:
- pyarrow>=12.0.1
- pyiceberg>=0.7.1
- pymysql>=1.1.0
- pyqt>=5.15.9
- pyreadstat>=1.2.6
- pytables>=3.8.0
- python-calamine>=0.1.7
Expand All @@ -71,4 +70,5 @@ dependencies:
- pandas-datareader
- pyyaml
- pip:
- PyQt6>=6.7.1
- tzdata>=2023.3
2 changes: 1 addition & 1 deletion ci/deps/actions-313.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ dependencies:
- numexpr>=2.9.0
- odfpy>=1.4.1
- qtpy>=2.3.0
- pyqt>=5.15.9
- openpyxl>=3.1.2
- psycopg2>=2.9.9
- pyarrow>=12.0.1
Expand All @@ -60,4 +59,5 @@ dependencies:
- zstandard>=0.22.0

- pip:
- PyQt6>=6.7.1
- tzdata>=2023.3
12 changes: 6 additions & 6 deletions doc/source/getting_started/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,12 @@ Clipboard

Installable with ``pip install "pandas[clipboard]"``.

======================================================================================== ================== =============== ==============
Dependency Minimum Version pip extra Notes
======================================================================================== ================== =============== ==============
`PyQt4 <https://pypi.org/project/PyQt4/>`__/`PyQt5 <https://pypi.org/project/PyQt5/>`__ 5.15.9 clipboard Clipboard I/O
`qtpy <https://github.com/spyder-ide/qtpy>`__ 2.3.0 clipboard Clipboard I/O
======================================================================================== ================== =============== ==============
======================================================================================================================================== ================== =============== ==============
Dependency Minimum Version pip extra Notes
======================================================================================================================================== ================== =============== ==============
`PyQt4 <https://pypi.org/project/PyQt4/>`__/`PyQt5 <https://pypi.org/project/PyQt5/>`__/`PyQt6 <https://pypi.org/project/PyQt6/>`__ 5.15.9 clipboard Clipboard I/O
`qtpy <https://github.com/spyder-ide/qtpy>`__ 2.3.0 clipboard Clipboard I/O
======================================================================================================================================== ================== =============== ==============

.. note::

Expand Down
2 changes: 1 addition & 1 deletion doc/source/user_guide/io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3928,7 +3928,7 @@ We can see that we got the same content back, which we had earlier written to th

.. note::

You may need to install xclip or xsel (with PyQt5, PyQt4 or qtpy) on Linux to use these methods.
You may need to install xclip or xsel (with PyQt6, PyQt5, PyQt4 or qtpy) on Linux to use these methods.

.. _io.pickle:

Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Other enhancements
- :meth:`pandas.concat` will raise a ``ValueError`` when ``ignore_index=True`` and ``keys`` is not ``None`` (:issue:`59274`)
- :py:class:`frozenset` elements in pandas objects are now natively printed (:issue:`60690`)
- Add ``"delete_rows"`` option to ``if_exists`` argument in :meth:`DataFrame.to_sql` deleting all records of the table before inserting data (:issue:`37210`).
- Added PyQt6 support to resolve ARM64 container build issues (:issue:`61037`)
- Added half-year offset classes :class:`HalfYearBegin`, :class:`HalfYearEnd`, :class:`BHalfYearBegin` and :class:`BHalfYearEnd` (:issue:`60928`)
- Added support to read and write from and to Apache Iceberg tables with the new :func:`read_iceberg` and :meth:`DataFrame.to_iceberg` functions (:issue:`61383`)
- Errors occurring during SQL I/O will now throw a generic :class:`.DatabaseError` instead of the raw Exception type from the underlying driver manager library (:issue:`60748`)
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ dependencies:
- pytest-xdist>=3.4.0
- pytest-qt>=4.4.0
- pytest-localserver
- pyqt>=5.15.9
- coverage

# required dependencies
Expand Down Expand Up @@ -122,4 +121,5 @@ dependencies:
- jupyterlite-pyodide-kernel

- pip:
- PyQt6>=6.7.1
- tzdata>=2023.3
2 changes: 1 addition & 1 deletion pandas/compat/_optional.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"xlsxwriter": "3.2.0",
"zstandard": "0.22.0",
"qtpy": "2.3.0",
"pyqt5": "5.15.9",
"PyQt6": "6.7.1",
}

# A mapping from import name to package name (on PyPI) for packages where
Expand Down
80 changes: 50 additions & 30 deletions pandas/io/clipboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
sudo apt-get install xsel
sudo apt-get install wl-clipboard

Otherwise on Linux, you will need the PyQt5 modules installed.
Otherwise on Linux, you will need the PyQt6 modules installed.

This module does not work with PyGObject yet.

Expand Down Expand Up @@ -55,6 +55,7 @@
get_errno,
sizeof,
)
import importlib
import os
import platform
from shutil import which as _executable_exists
Expand Down Expand Up @@ -133,18 +134,51 @@ def paste_osx_pyobjc():
return copy_osx_pyobjc, paste_osx_pyobjc


def init_qt_clipboard():
global QApplication
# $DISPLAY should exist
def _import_module(modules: list[tuple[str, str | None]]):
"""
Attempt to import from a module from a list inorder.

Args:
modules: A list of tuples of two elements. The first element
is the module to import from and the second element is
the object to import. If the second element is not provided,
just import the module.

Returns:
The first successful import.

# Try to import from qtpy, but if that fails try PyQt5 then PyQt4
try:
from qtpy.QtWidgets import QApplication
except ImportError:
Raises:
ImportError: If couldn't import any module.
AttributeError: If a module doesn't have the expected attribute.
"""

for module_name, attribute_name in modules:
try:
from PyQt5.QtWidgets import QApplication
module = importlib.import_module(module_name)

if attribute_name is None:
return module
return getattr(module, attribute_name)

except ImportError:
from PyQt4.QtGui import QApplication
continue

raise ImportError(
f"No module from {tuple(module_name for module_name, _ in modules)} could be imported."
)


def init_qt_clipboard():
# $DISPLAY should exist
global QApplication

qt_qapplication_bindings = [
("qtpy.QtWidgets", "QApplication"),
("PyQt6.QtWidgets", "QApplication"),
("PyQt5.QtWidgets", "QApplication"),
("PyQt4.QtGui", "QApplication"),
]
QApplication = _import_module(qt_qapplication_bindings)

app = QApplication.instance()
if app is None:
Expand Down Expand Up @@ -529,7 +563,7 @@ def determine_clipboard():
Determine the OS/platform and set the copy() and paste() functions
accordingly.
"""
global Foundation, AppKit, qtpy, PyQt4, PyQt5
global Foundation, AppKit

# Setup for the CYGWIN platform:
if (
Expand Down Expand Up @@ -576,25 +610,11 @@ def determine_clipboard():
return init_klipper_clipboard()

try:
# qtpy is a small abstraction layer that lets you write applications
# using a single api call to either PyQt or PySide.
# https://pypi.python.org/project/QtPy
import qtpy # check if qtpy is installed
except ImportError:
# If qtpy isn't installed, fall back on importing PyQt4.
try:
import PyQt5 # check if PyQt5 is installed
except ImportError:
try:
import PyQt4 # check if PyQt4 is installed
except ImportError:
pass # We want to fail fast for all non-ImportError exceptions.
else:
return init_qt_clipboard()
else:
return init_qt_clipboard()
else:
# Verify installation of pyqt, PyQt{6,5,4} and initialize its clipboard.
return init_qt_clipboard()
except ImportError:
# Ignore if Qt isn't available
pass

return init_no_clipboard()

Expand All @@ -618,7 +638,7 @@ def set_clipboard(clipboard):
clipboard_types = {
"pbcopy": init_osx_pbcopy_clipboard,
"pyobjc": init_osx_pyobjc_clipboard,
"qt": init_qt_clipboard, # TODO - split this into 'qtpy', 'pyqt4', and 'pyqt5'
"qt": init_qt_clipboard, # TODO - split this into 'qtpy', 'pyqt4', 'pyqt5' and 'pyqt6'
"xclip": init_xclip_clipboard,
"xsel": init_xsel_clipboard,
"wl-clipboard": init_wl_clipboard,
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ html = ['beautifulsoup4>=4.12.3', 'html5lib>=1.1', 'lxml>=4.9.2']
xml = ['lxml>=4.9.2']
plot = ['matplotlib>=3.8.3']
output-formatting = ['jinja2>=3.1.3', 'tabulate>=0.9.0']
clipboard = ['PyQt5>=5.15.9', 'qtpy>=2.3.0']
clipboard = ['PyQt6>=6.7.1', 'qtpy>=2.3.0']
compression = ['zstandard>=0.22.0']
timezone = ['pytz>=2023.4']
all = ['adbc-driver-postgresql>=1.2.0',
Expand All @@ -99,7 +99,7 @@ all = ['adbc-driver-postgresql>=1.2.0',
'pyarrow>=12.0.1',
'pyiceberg>=0.7.1',
'pymysql>=1.1.0',
'PyQt5>=5.15.9',
'PyQt6>=6.7.1',
'pyreadstat>=1.2.6',
'pytest>=7.3.2',
'pytest-xdist>=3.4.0',
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pytest-cov
pytest-xdist>=3.4.0
pytest-qt>=4.4.0
pytest-localserver
PyQt5>=5.15.9
coverage
python-dateutil
numpy<3
Expand Down Expand Up @@ -85,4 +84,5 @@ requests
pygments
jupyterlite-core
jupyterlite-pyodide-kernel
PyQt6>=6.7.1
tzdata>=2023.3
2 changes: 1 addition & 1 deletion scripts/generate_pip_deps_from_conda.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"dask-core": "dask",
"seaborn-base": "seaborn",
"sqlalchemy": "SQLAlchemy",
"pyqt": "PyQt5",
"pyqt": "PyQt6",
}


Expand Down
4 changes: 2 additions & 2 deletions scripts/tests/data/deps_minimum.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ html = ['beautifulsoup4>=4.9.3', 'html5lib>=1.1', 'lxml>=4.6.3']
xml = ['lxml>=4.6.3']
plot = ['matplotlib>=3.6.1']
output_formatting = ['jinja2>=3.0.0', 'tabulate>=0.8.9']
clipboard = ['PyQt5>=5.15.1', 'qtpy>=2.3.0']
clipboard = ['PyQt6>=6.7.1', 'qtpy>=2.3.0']
compression = ['zstandard>=0.15.2']
all = ['beautifulsoup4>=5.9.3',
'bottleneck>=1.3.2',
Expand All @@ -90,7 +90,7 @@ all = ['beautifulsoup4>=5.9.3',
'psycopg2>=2.9.9',
'pyarrow>=7.0.0',
'pymysql>=1.1.0',
'PyQt5>=5.15.1',
'PyQt6>=6.7.1',
'pyreadstat>=1.1.2',
'pytest>=7.3.2',
'pytest-xdist>=3.4.0',
Expand Down
Loading