2024-01-31

今年は CentOS Stream 10 が登場

CentOS Stream は、継続的に提供される Red Hat® Enterprise Linux (RHEL) のディストリビューション・アップストリームを、オープンソース・コミュニティのメンバーが Red Hat の開発者と連携して開発、テスト、貢献することができる、Linux® ディストリビューションです。

参考サイト [1] より引用

CentOS 8 の開発終了がアナウンスされたのは 2020 年 12 月 8 日のことでした [2]。当時はこのアナウンスに慌てましたが、AlmaLinuxRocky Linux の登場で RHEL 互換 OS の選択に困ることがなくなりました。

CentOS 8 の開発が終了して、残った CentOS Stream 8 も、RHEL 8 のフルサポートフェーズが終わる日と同じ、2024 年 5 月 31 日にサポートが終了します [3]。CentOS Stream が CentOS の代替にならない大きな理由は、RHEL のアップストリームであることですが、EOL が RHEL のフルサポートフェーズ終了日(現在は5年)というサポート期間の短さも理由のひとつとしてあげられるでしょう。

しかし、デスクトップ用途の PC の OS に Fedora Linux を使っている者としては、CentOS Stream が RHEL のちょっと先行くディストロなので、個人的なサーバー用途としては、変化の激しい Fedora Linux よりも魅力的ではあります。しかも(3年毎ぐらいに)次の RHEL がリリースされれば新しい方に移行することを考えるので、5年というサポート期間はそれほど短いとも言えません。

※ 実際には本番環境に RHEL 9、テスト環境に AlmaLinux 9 を使用しています。😅

CentOS Stream 9 のデスクトップ画面

その後リリースされた RHEL 9  [5] は、先にリリースされた CentStream 9 をベースにビルドされてリリースされました。

今年は 2025 年にリリース予定の RHEL 10 のアップストリームとして、CentOS Stream 10 がリリースされる年です [7]。と言っても、Fedora Linux 40(現在のところ 4 月 16 日リリース予定 [8])をベースにするようですので、CentOS Stream 10 が一般公開されるのは、もしかすると CentOS Stream 8 が EOL になってからなのかもしれません。

Fedora Linux 40 のリポジトリが Fedora Rawhide からブランチするのが 2 月 13 日に予定されていますので、気の早い考えをすると、このブランチ以降で CentOS Stream 10 にもなにか動きがあるかもしれません。

いずれにしても、CentOS Stream 10 の動きに注視を続け、なにか動きがあれば、当ブログで紹介したいと考えています。

参考サイト

  1. CentOS Stream とは | Red Hat
  2. CentOS Project shifts focus to CentOS Stream – Blog.CentOS.org [2020-12-08]
  3. Product Life Cycles | Red Hat Customer Portal
  4. Red Hat Enterprise Linux のライフサイクル - Red Hat Customer Portal
  5. CentOS Stream入門 - 赤帽エンジニアブログ [2021-03-19]
  6. いよいよ登場:Red Hat Enterprise Linux 9 [2022-05-18]
  7. CentOS Stream 10 Starting To Get Underway, More Activity In 2024 - Phoronix [2023-06-17]
  8. Fedora Linux 40 Schedule: Key

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



2024-01-30

QThreadPool を使う ~ PySide6

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

以前、本ブログで PySide2 と mplfinance を組み合わせた GUI サンプルを紹介しました [1]。また、PySide6 に GUI ライブラリを更新したサンプルも既に紹介しています [2]

今回は yfinance の API を利用して株価データを取得する部分を、QThreadPool / QRunnable で別スレッドにして読み込むようにしました。データの読み込みにそれほど時間が掛かるわけでもないのですが、スレッドの練習題材にしたくて、ローソク足チャートのサンプルを再び取り上げました。

下記の OS 環境で動作確認をしています。

Fedora Workstation 39 x86_64
Python 3.12.1
PySide6 6.6.1
matplotlib 3.8.2
mplfinance 0.12.10b0
pandas 2.2.0
yfinance 0.2.36

サンプル

サンプルはあまりコンパクトにできなかったので、下記の4つのファイルに分けました。

  • qt_mpl_finance_2.py
    • GUI サンプルのメイン
  • qt_mpl_finance_2_func.py
    • 関数処理
  • qt_mpl_finance_2_sub.py
    • GUI のサブ・コンポーネント
  • qt_mpl_finance_2_thread.py
    • QRunner によるスレッド処理

qt_mpl_finance_2.py は、本サンプルのメイン部分で、下記の GUI を QMainWindow で構成しています。

qt_mpl_finance_2.py の実行例 (1)
qt_mpl_finance_2.py
import pandas as pd
import sys
from PySide6.QtCore import (
QThreadPool,
Qt,
)
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QWidget,
)
from qt_mpl_finance_2_func import draw_chart
from qt_mpl_finance_2_sub import (
DockNavigator,
MyToolBar,
StockChart,
)
from qt_mpl_finance_2_thread import ThreadWorker
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.threadpool = QThreadPool()
self.init_ui()
self.setWindowTitle('Candlestick chart')
self.resize(800, 600)
def init_ui(self):
toolbar = MyToolBar()
toolbar.tickerEntered.connect(self.on_ticker_entered)
self.addToolBar(toolbar)
chart = StockChart()
self.setCentralWidget(chart)
dock_bottom = DockNavigator(chart)
self.addDockWidget(
Qt.DockWidgetArea.BottomDockWidgetArea,
dock_bottom
)
def on_ticker_entered(self, ticker: str):
worker = ThreadWorker(ticker)
worker.finished.connect(self.on_draw_chart)
self.threadpool.start(worker)
def on_draw_chart(self, ticker: str, df: pd.DataFrame):
chart: QWidget | StockChart = self.centralWidget()
draw_chart(chart, ticker, df)
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

qt_mpl_finance_2_func.py は、yfinance で株価データを読み込む処理と、mplfinance でデータフレームをキャンバス上に描画する処理を関数としてまとめてあります。

qt_mpl_finance_2_func.py
import mplfinance as mpf
import pandas as pd
import yfinance as yf
from qt_mpl_finance_2_sub import StockChart
def draw_chart(chart:StockChart, ticker:str, df:pd.DataFrame):
chart.clearAxes()
chart.ax.set_title(ticker)
mpf.plot(
df,
type='candle',
datetime_format='%m/%d',
mav=(5, 25),
tight_layout=False,
style='yahoo',
ax=chart.ax,
volume=chart.ax2
)
chart.ax.grid()
chart.ax2.grid()
chart.refreshDraw()
def get_trade_info(ticker: str) -> pd.DataFrame:
df = yf.download(ticker, period='3mo')
return df

qt_mpl_finance_2_sub.py は、メインの QMainWindow の GUI を構成する、ツールバー、中心部のチャート用のキャンバス、Matplotlib のナビゲーション・ツールバーを表示する下部のドックを記述しています。

qt_mpl_finance_2_sub.py
from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
QDockWidget,
QLineEdit,
QToolBar,
QWidget,
)
from matplotlib import pyplot as plt
from matplotlib.backends.backend_qtagg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
class DockNavigator(QDockWidget):
def __init__(self, canvas):
super().__init__()
self.setTitleBarWidget(QWidget(None))
navtoolbar = NavigationToolbar(canvas, self)
self.setWidget(navtoolbar)
class MyToolBar(QToolBar):
tickerEntered = Signal(str)
def __init__(self):
super().__init__()
ent_ticker = QLineEdit()
ent_ticker.setFixedWidth(100)
ent_ticker.returnPressed.connect(self.on_ticker_entered)
self.addWidget(ent_ticker)
def on_ticker_entered(self):
entry: QLineEdit = self.sender()
ticker = entry.text()
self.tickerEntered.emit(ticker)
class StockChart(FigureCanvas):
plt.rcParams['font.family'] = plt.rcParams['font.monospace'][0]
plt.rcParams['font.size'] = 9
def __init__(self):
self.fig = Figure()
super().__init__(self.fig)
grid = plt.GridSpec(3, 1, wspace=0.0, hspace=0.0)
self.ax = self.fig.add_subplot(grid[0:2, 0])
self.ax2 = self.fig.add_subplot(grid[2, 0], sharex=self.ax)
def clearAxes(self):
self.ax.cla()
self.ax2.cla()
def refreshDraw(self):
self.fig.canvas.draw()

qt_mpl_finance_2_thread.py は、yfinance で株価データを読み込む処理を別スレッドで実行する QRunnable クラスを継承した ThreadWorker クラスです。

qt_mpl_finance_2_thread.py
import pandas as pd
from PySide6.QtCore import (
QObject,
QRunnable,
Signal,
)
from qt_mpl_finance_2_func import get_trade_info
class ThreadWorkerSignal(QObject):
finished = Signal(str, pd.DataFrame)
class ThreadWorker(QRunnable, ThreadWorkerSignal):
def __init__(self, ticker: str):
super().__init__()
self.ticker = ticker
def run(self):
df = get_trade_info(self.ticker)
self.finished.emit(self.ticker, df)

QRunnable クラスを継承した ThreadWorker のインスタンスでは、別スレッドで処理を実行させることができますが、そのままでは、処理の終了や結果を Signal を発して親スレッドへ送ることができません。そのため、このサンプルでは、QObject を継承したシグナル専用のクラス ThreadWorkerSignal を作成しておいて、QRunnable と一緒に多重継承して、ThreadWorkerSignal で定義したシグナルを利用できるようにしています。

class ThreadWorkerSignal(QObject):
    finished = Signal(str, pd.DataFrame)
 
 
class ThreadWorker(QRunnable, ThreadWorkerSignal):
    def __init__(self, ticker: str):
        super().__init__()
        self.ticker = ticker
 
    def run(self):
        df = get_trade_info(self.ticker)
        self.finished.emit(self.ticker, df)

この ThreadWorker は、本体 qt_mpl_finance_2.py 側で、下記のメソッド内でインスタンス worker を生成して、QThreadPool のインスタンス self.threadpoolstart メソッドにインスタンス worker を渡します。この start メソッドが実行されると、別スレッドで worker.run() が実行されます。

def on_ticker_entered(self, ticker: str):
    worker = ThreadWorker(ticker)
    worker.finished.connect(self.on_draw_chart)
    self.threadpool.start(worker)

worker の処理が終わると、finished シグナルが発せられるので、これを self.on_draw_chart メソッド(スロット)で処理します。

def on_draw_chart(self, ticker: str, df: pd.DataFrame):
    chart: QWidget | StockChart = self.centralWidget()
    draw_chart(chart, ticker, df)

サンプルの使い方

東証に上場している銘柄であれば、ツールボックスの QLineEdit のインスタンスに、銘柄コードに .T を付加した文字列(例 1301.T)を入力して Enter すると、過去3ヶ月分の日足チャートが出力されます。

qt_mpl_finance_2.py の実行例 (2)

日経平均の指数は ^N255 と入力して Enter します。米国銘柄はアルファベットのシンボルを入力します。

qt_mpl_finance_2.py の実行例 (3)

サンプルということで、存在しないコードを入力したときなどのエラー処理は一切していません。🙇🏻

参考サイト

  1. bitWalk's: ローソク足チャート ~ python/mplfinance [2021-05-02]
  2. bitWalk's: ローソク足チャート ~ PySide6, mplfinance [2023-08-15]
  3. QThreadPool - Qt for Python
  4. QRunnable - Qt for Python
  5. ranaroussi/yfinance: Download market data from Yahoo! Finance's API
  6. matplotlib/mplfinance: Financial Markets Data Visualization using Matplotlib

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



2024-01-28

QMediaPlayer を使ってみる ~ PySide6

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

Qt ライブラリの機能は GUI 部品にとどまらず、とても広範なので、使ったことの無い機能がたくさんあります。今回は、そのうち、動画再生に利用できる QMediaPlayer で MP4 ファイルを再生する簡単なサンプルを紹介します。

下記の OS 環境で動作確認をしています。

Fedora Workstation 39 x86_64
Python 3.12.1
PySide6 6.6.1

以下のスクリーンショットは、参考サイト [4] から MP4 ファイルをダウンロードして、それを読み込んで再生している例です。

qt_mediaplayer.py の実行例

サンプルは、ツールバーの部分である MyToolBar クラスと、本体 Example クラスに分けました。

qt_mediaplayer_toolbar.py
from PySide6.QtCore import Signal
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import (
QFileDialog,
QStyle,
QToolBar,
QToolButton,
QWidget,
)
def get_icon(parent: QWidget, name: str) -> QIcon:
pixmap = getattr(QStyle.StandardPixmap, name)
icon = parent.style().standardIcon(pixmap)
return icon
class MyToolBar(QToolBar):
playVideo = Signal()
readVideo = Signal(str)
def __init__(self):
super().__init__()
# Ioen
but_open = QToolButton()
but_open.setIcon(get_icon(self, 'SP_DirIcon'))
but_open.clicked.connect(self.on_clicked_open)
self.addWidget(but_open)
# Play
but_play = QToolButton()
but_play.setIcon(get_icon(self, 'SP_MediaPlay'))
but_play.clicked.connect(self.on_clicked_play)
self.addWidget(but_play)
def on_clicked_open(self):
dialog = QFileDialog()
dialog.setWindowTitle('Open video file')
dialog.setNameFilter('Video (*.mp4)')
if dialog.exec():
filename = dialog.selectedFiles()[0]
self.readVideo.emit(filename)
def on_clicked_play(self):
self.playVideo.emit()
qt_mediaplayer.py
#!/usr/bin/env python
# coding: utf-8
import sys
from PySide6.QtCore import QUrl
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtMultimediaWidgets import QVideoWidget
from PySide6.QtWidgets import QApplication, QMainWindow
from qt_mediaplayer_toolbar import MyToolBar, get_icon
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.player = QMediaPlayer()
self.init_audio()
self.init_video()
self.setWindowIcon(get_icon(self, 'SP_TitleBarMenuButton'))
self.setWindowTitle('Media Player')
self.resize(600, 400)
def init_audio(self):
audio = QAudioOutput(self)
self.player.setAudioOutput(audio)
audio.setVolume(50)
def init_video(self):
toolbar = MyToolBar()
toolbar.readVideo.connect(self.on_read_video)
toolbar.playVideo.connect(self.on_play_video)
self.addToolBar(toolbar)
video = QVideoWidget(self)
self.player.setVideoOutput(video)
self.setCentralWidget(video)
def on_read_video(self, filename: str):
self.player.setSource(QUrl.fromLocalFile(filename))
def on_play_video(self):
self.player.play()
def main():
app = QApplication(sys.argv)
win = Example()
win.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()

サンプルを実行すると下記のようなメッセージが出ます。メッセージが出ても MP4 のファイルの再生はできているのですが、メッセージの解消方法が判れば追記します。

(venv) $ python qt_mediaplayer.py
qt.multimedia.ffmpeg.libsymbolsresolver: Couldn't load VAAPI library

このサンプルは、MP4 ファイルを読み込んで、再生するだけのものです。

サンプルの大まかな流れは、まず QMediaPlayer のインスタンス self.player を作成し、QAudioOutput で音、QVideoWidget で動画の出力先のインスタンスをそれぞれ作成して self.player に登録します。

self.player = QMediaPlayer()
 
audio = QAudioOutput(self)
self.player.setAudioOutput(audio)
 
video = QVideoWidget(self)
self.player.setVideoOutput(video)

MP4 ファイル filenameself.player に読み込んで play メソッドで再生します。

self.player.setSource(QUrl.fromLocalFile(filename))
 
self.player.play()

QMediaPlayer の機能を試しながら、もっと使いこなせるようにしていきたいです。

参考サイト

  1. QMediaPlayer - Qt for Python
  2. QAudioOutput - Qt for Python
  3. QVideoWidget - Qt for Python
  4. Download Sample Videos / Dummy Videos For Demo Use
  5. Video Overview | Qt Multimedia 6.6.1

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



2024-01-23

KDE neon testing 版の KDE Plasma 6

KDE Plasma は、主に Linux 向けに開発されているデスクトップ環境です。現在リリースされている KDE Plasma 5 は、Qt 5 ライブラリを利用していますが、その後継である Qt 6 を利用した KDE Plasma 6 がリリースに向けて開発中です。

1 月 10 日(現地時間)に、KDE プロジェクトから現在開発中の次期 KDE Plasma 6 のリリース候補 RC 1 (5.92.0) のリリースがアナウンスされましたが [1]、KDE neon unstable 版は KDE Plasma 6.1 へ開発が移り、当時の KDE neon testing 版ではパッケージの更新をうまくできませんでした。幸い、すぐに Fedora Rawhide の方で KDE Plasma 6 RC1 を確認できたので、そちらの方を当ブログでは紹介しました [2]

今日、KDE neon testing 版のパッケージが 20240222-1309 に更新されていたので、ダウンロードして GNOME Boxes の仮想環境にインストールしました。デスクトップ環境が KDE Plasma 6 RC1 (5.92.90) になっていることを確認しました。KDE Plasma の開発プロジェクトがリリースしている版だからでしょうか、バージョン番号は Fedora Rawhide のもの (5.92.0) より進んでいます。

GNOME Boxes 上にインストールした neon-testing-20240222-1309.iso

リリース候補版になって壁紙も一新されました。

参考サイト

  1. KDE's 6th Megarelease - Release Candidate 1 - KDE Community [2024-01-10]
  2. bitWalk's: KDE Plasma 6 RC 1 リリース [2024-01-15]
  3. KDE neon

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



2024-01-21

QCalendarWidget と QDate ~ PySide6

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

python で日付や時間情報を扱う時にはもっぱら datetime モジュールを利用してきました。しかし GUI ライブラリに PySide6 を利用するのであれば、日付や時間情報も QDate あるいは QDateTime クラスを利用した方が便利のように思えます。

簡単なサンプルの作成を重ねて評価しようと、今回は QCalendarWidget と QDate をサンプルにしてみました。

下記の OS 環境で動作確認をしています。

Fedora Workstation 39 x86_64
Python 3.12.1
PySide6 6.6.1

サンプルを下記に示しました。

qt_calendar.py
#!/usr/bin/env python
# coding: utf-8
import sys
from PySide6.QtCore import QDate
from PySide6.QtWidgets import (
QApplication,
QCalendarWidget,
QLineEdit,
QMainWindow,
QStyle,
QToolBar,
QToolButton,
)
class DateEntry(QLineEdit):
def __init__(self):
super().__init__()
self.qdate: QDate | None = None
self.setEnabled(False)
def getDate(self) -> QDate | None:
return self.qdate
def setDate(self, qdate: QDate):
self.qdate = qdate
self.setText('{:0=4}-{:0=2}-{:0=2}'.format(
qdate.year(), qdate.month(), qdate.day()
))
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.calendar: QCalendarWidget | None = None
toolbar = QToolBar()
self.addToolBar(toolbar)
self.entry = DateEntry()
toolbar.addWidget(self.entry)
but_calendar = QToolButton()
icon = self.style().standardIcon(QStyle.StandardPixmap.SP_DialogApplyButton)
but_calendar.setIcon(icon)
but_calendar.clicked.connect(self.on_clicked)
toolbar.addWidget(but_calendar)
def on_date_selected(self, qdate: QDate):
self.entry.setDate(qdate)
if self.calendar is not None:
self.calendar.hide()
self.calendar.deleteLater()
def on_clicked(self):
self.calendar = QCalendarWidget()
qdate = self.entry.getDate()
if qdate is not None:
self.calendar.setSelectedDate(qdate)
self.calendar.activated.connect(self.on_date_selected)
self.calendar.show()
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
view raw qt_calendar.py hosted with ❤ by GitHub

このサンプルを実行すると、ツールバーを持った QMainWindow クラスのインスタンスが表示されます。ツールバー上の右側にある Apply ボタンをクリックすると QCalendarWidget クラスのインスタンス(カレンダーと呼びます)が表示されます。ツールバー上の左側にある DateEntry クラスのインスタンスに日付が表示されていればその日付が、そうでなければ本日の日付が選択状態(青色)になります。

マウスでカレンダー上の日付を選択してダブルクリックすると、カレンダーが閉じられます。その際、カレンダーは選択された日付を QDate のインスタンスで返します。

qt_calendar.py の実行例

返された日付は、ツールバーの左側にある DateEntry クラスのインスタンス上に表示されます。DateEntry は QLineEidt を継承したクラスで、setDate メソッドで渡された QDate の日付情報をそのままインスタンスで保持し、yyyy-mm-dd の文字列に整形して表示します。

参考サイト

  1. datetime --- 基本的な日付型および時間型
  2. QDate - Qt for Python
  3. QDateTime - Qt for Python

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



2024-01-15

KDE Plasma 6 RC 1 リリース

KDE Plasma は、主に Linux 向けに開発されているデスクトップ環境です。現在リリースされている KDE Plasma 5 は、Qt 5 ライブラリを利用していますが、その後継である Qt 6 を利用した KDE Plasma 6 がリリースに向けて開発中です。

1 月 10 日(現地時間)に、現在開発中の次期 KDE Plasma 6 の Release Candidate 1 (5.92.0) のリリースが KDE プロジェクトからアナウンスされました [1]

KDE プロジェクトがリリースしている Linux ディストロ KDE neon の unstable 版 [2] に反映されるのを待っていたのですが、今回は、Fedora Rawhide Spins の KDE 版 [3] の方が反映されるのが早かったようです。更新したところ、壁紙の右下の文字列が KDE Plasma 6 RC1 になりました。

GNOME Boxes 上にインストールした Fedora Rawhide KDE を最新にアップデート(1/15 時点)

※ KDE neon の unstable 版は、'KDE Plasma 6.1 Dev' になって、6.1 の開発に移っていました。[2024-01-16]

参考サイト

  1. KDE's 6th Megarelease - Release Candidate 1 - KDE Community [2024-01-10]
  2. KDE neon
  3. https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Spins/x86_64/iso/
  4. Schedules/Plasma 6 - KDE Community Wiki

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース