Skip to content

Commit 4eca578

Browse files
committed
Upgrade tests to support Python 3.13
1 parent 3062aaa commit 4eca578

File tree

9 files changed

+63
-48
lines changed

9 files changed

+63
-48
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
33
name: CI
44

5-
on: [push, pull_request]
5+
on: [ push, pull_request ]
66

77
jobs:
88
ci:
99
strategy:
1010
matrix:
11-
os: [ubuntu-latest, macos-latest, windows-latest]
12-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
11+
os: [ ubuntu-latest, macos-latest, windows-latest ]
12+
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ]
1313
fail-fast: false
1414
runs-on: ${{ matrix.os }}
1515
steps:

.github/workflows/doc.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
33
name: Doc
44

5-
on: [push, pull_request]
5+
on: [ push, pull_request ]
66

77
permissions:
88
contents: read
@@ -11,8 +11,8 @@ jobs:
1111
doc:
1212
strategy:
1313
matrix:
14-
os: [ubuntu-latest]
15-
python-version: ["3.12"]
14+
os: [ ubuntu-latest ]
15+
python-version: [ "3.13" ]
1616
fail-fast: false
1717
runs-on: ${{ matrix.os }}
1818
steps:

.github/workflows/format.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
33
name: Format
44

5-
on: [push, pull_request]
5+
on: [ push, pull_request ]
66

77
permissions:
88
contents: read
@@ -11,8 +11,8 @@ jobs:
1111
lint:
1212
strategy:
1313
matrix:
14-
os: [ubuntu-latest]
15-
python-version: ["3.12"]
14+
os: [ ubuntu-latest ]
15+
python-version: [ "3.13" ]
1616
fail-fast: false
1717
runs-on: ${{ matrix.os }}
1818
steps:

.github/workflows/lint.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
33
name: Lint
44

5-
on: [push, pull_request]
5+
on: [ push, pull_request ]
66

77
permissions:
88
contents: read
@@ -11,8 +11,8 @@ jobs:
1111
lint:
1212
strategy:
1313
matrix:
14-
os: [ubuntu-latest]
15-
python-version: ["3.12"]
14+
os: [ ubuntu-latest ]
15+
python-version: [ "3.13" ]
1616
fail-fast: false
1717
runs-on: ${{ matrix.os }}
1818
steps:

.github/workflows/mypy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
33
name: MyPy
44

5-
on: [push, pull_request]
5+
on: [ push, pull_request ]
66

77
permissions:
88
contents: read
@@ -11,8 +11,8 @@ jobs:
1111
mypy:
1212
strategy:
1313
matrix:
14-
os: [ubuntu-latest]
15-
python-version: ["3.12"]
14+
os: [ ubuntu-latest ]
15+
python-version: [ "3.13" ]
1616
fail-fast: false
1717
runs-on: ${{ matrix.os }}
1818
steps:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ Pipfile.lock
4343

4444
# pyenv version file
4545
.python-version
46+
47+
# uv
48+
uv.lock

Pipfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ url = "https://pypi.org/simple"
44
verify_ssl = true
55

66
[packages]
7-
pyperclip = ">=1.6"
8-
setuptools = ">=34.4"
9-
wcwidth = ">=0.1.7"
7+
pyperclip = "*"
8+
setuptools = "*"
9+
wcwidth = "*"
1010

1111
[dev-packages]
1212
black = "*"
@@ -24,6 +24,7 @@ pyreadline3 = {version = ">=3.4",sys_platform = "== 'win32'"}
2424
pytest = "*"
2525
pytest-cov = "*"
2626
pytest-mock = "*"
27+
ruff = "*"
2728
sphinx = "*"
2829
sphinx-autobuild = "*"
2930
sphinx-rtd-theme = "*"

docs/features/scripting.rst

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,25 @@ command. Here's a simple example that uses the arg_printer_ script::
8484
system paths, and as shown above it has the ability to pass command-line
8585
arguments to the scripts invoked.
8686

87-
Developing a CMD2 API
87+
Developing a CMD2 API
8888
---------------------
8989

9090
If you as an app designer have not explicitly disabled the run_pyscript command it must be assumed
9191
that your application is structured for use in higher level python scripting. The following sections
9292
are meant as guidelines and highlight possible pitfalls with both production and consumption
9393
of API functionality. For clarity when speaking of "scripter" we are referring to those writing
94-
scripts to be run by pyscript and "designer" as the CMD2 application author.
94+
scripts to be run by pyscript and "designer" as the CMD2 application author.
9595

9696
Basics
9797
~~~~~~
9898

9999
Without any work on the part of the designer, a scripter can take advantage of piecing together workflows
100-
using simple ``app`` calls. The result of a run_pyscript app call yields a ``CommandResult`` object exposing
101-
four members: ``Stdout``, ``Stderr``, ``Stop``, and ``Data``.
100+
using simple ``app`` calls. The result of a run_pyscript app call yields a ``CommandResult`` object exposing
101+
four members: ``Stdout``, ``Stderr``, ``Stop``, and ``Data``.
102102

103103
``Stdout`` and ``Stderr`` are fairly straightforward representations of normal data streams and accurately reflect
104-
what is seen by the user during normal cmd2 interaction. ``Stop`` contains information about how the invoked
105-
command has ended its lifecycle. Lastly ``Data`` contains any information the designer sets via ``self.last_result``
104+
what is seen by the user during normal cmd2 interaction. ``Stop`` contains information about how the invoked
105+
command has ended its lifecycle. Lastly ``Data`` contains any information the designer sets via ``self.last_result``
106106
or ``self._cmd.last_result`` if called from inside a CommandSet.
107107

108108

@@ -118,7 +118,7 @@ where:
118118
* ``command`` and ``args`` are entered exactly like they would be entered by
119119
a user of your application.
120120

121-
Using fstrings tends to be the most straight forward and easily readable way to
121+
Using fstrings tends to be the most straight forward and easily readable way to
122122
provide parameters.::
123123

124124
first = 'first'
@@ -136,7 +136,7 @@ Design principles
136136
If the cmd2 application follows the unix_design_philosophy_ a scriptor will have the most flexibility
137137
to piece together workflows using different commands. If the designers' application is more complete
138138
and less likely to be augmented in the future a scripter may opt for simple serial scripts with little
139-
control flow. In either case, choices made by the designer will have effects on scripters.
139+
control flow. In either case, choices made by the designer will have effects on scripters.
140140

141141
The following diagram illustrates the different boundaries to keep in mind.
142142

@@ -167,7 +167,7 @@ The following diagram illustrates the different boundaries to keep in mind.
167167
.. note::
168168

169169
As a designer it is preferable to design from the inside to out. Your code will be
170-
infinitely far easier to unit test than at the higher level. While there are
170+
infinitely far easier to unit test than at the higher level. While there are
171171
regression testing extensions for cmd2 UnitTesting will always be faster for development.
172172

173173
.. warning::
@@ -178,7 +178,7 @@ The following diagram illustrates the different boundaries to keep in mind.
178178
Developing a Basic API
179179
~~~~~~~~~~~~~~~~~~~~~~
180180

181-
CMD2 out of the box allows scripters to take advantage of all exposed ``do_*`` commands. As a
181+
CMD2 out of the box allows scripters to take advantage of all exposed ``do_*`` commands. As a
182182
scripter one can easily interact with the application via ``stdout`` and ``stderr``.
183183

184184
As a baseline lets start off with the familiar FirstApp
@@ -243,7 +243,7 @@ Lets start off on the wrong foot::
243243
^
244244
SyntaxError: unexpected EOF while parsing
245245

246-
cmd2 pyscripts require **valid** python code as a first step.
246+
cmd2 pyscripts require **valid** python code as a first step.
247247

248248
.. warning::
249249

@@ -253,7 +253,7 @@ cmd2 pyscripts require **valid** python code as a first step.
253253

254254
When executing the ``speak`` command without parameters you see the following error::
255255

256-
(Cmd) speak
256+
(Cmd) speak
257257
Usage: speak [-h] [-p] [-s] [-r REPEAT] words [...]
258258
Error: the following arguments are required: words
259259

@@ -264,19 +264,19 @@ Even though this is a fully qualified CMD2 error the py_script must look for thi
264264

265265
::
266266

267-
(Cmd) run_pyscript script.py
267+
(Cmd) run_pyscript script.py
268268
Working
269-
(Cmd)
269+
(Cmd)
270270

271-
You should notice that no error message is printed. Let's utilize the ``CommandResult``
271+
You should notice that no error message is printed. Let's utilize the ``CommandResult``
272272
object to inspect the actual returned data.::
273273

274274
result = app('speak')
275275
print(result)
276276

277277
::
278278

279-
(Cmd) run_pyscript script.py
279+
(Cmd) run_pyscript script.py
280280
CommandResult(stdout='', stderr='Usage: speak [-h] [-p] [-s] [-r REPEAT] words [...]\nError: the following arguments are required: words\n\n', stop=False, data=None)
281281

282282
Now we can see that there has been an error. Let's re write the script to perform error checking.::
@@ -288,7 +288,7 @@ Now we can see that there has been an error. Let's re write the script to perfor
288288

289289
::
290290

291-
(Cmd) run_pyscript script.py
291+
(Cmd) run_pyscript script.py
292292
Something went wrong
293293

294294
In python development is good practice to fail and exit quickly after user input.::
@@ -305,10 +305,10 @@ In python development is good practice to fail and exit quickly after user input
305305

306306
::
307307

308-
(Cmd) run_pyscript script.py
308+
(Cmd) run_pyscript script.py
309309
Continuing along..
310310

311-
We changed the input to be a valid ``speak`` command but no output. Again we must inspect the
311+
We changed the input to be a valid ``speak`` command but no output. Again we must inspect the
312312
``CommandResult``::
313313

314314
import sys
@@ -323,7 +323,7 @@ We changed the input to be a valid ``speak`` command but no output. Again we mus
323323

324324
::
325325

326-
(Cmd) run_pyscript script.py
326+
(Cmd) run_pyscript script.py
327327
TRUTH!!!
328328

329329
By just using ``stdout`` and ``stderr`` it is possible to string together commands
@@ -334,7 +334,7 @@ Developing an Advanced API
334334
~~~~~~~~~~~~~~~~~~~~~~~~~~
335335

336336
Until now the application designer has paid little attention to scripters and their needs.
337-
Wouldn't it be nice if while creating py_scripts one did not have to parse data from ``stdout``? We can
337+
Wouldn't it be nice if while creating py_scripts one did not have to parse data from ``stdout``? We can
338338
accomodate the weary scripter by adding one small line at the end of our ``do_*`` commands.
339339

340340
``self.last_result = <value>``
@@ -378,22 +378,22 @@ The following script retrieves the array contents.::
378378

379379
Results::
380380

381-
Cmd) run_pyscript script.py
381+
Cmd) run_pyscript script.py
382382
['.venv', 'app.py', 'script.py']
383383

384-
As a rule of thumb it is safer for the designer to return simple scalar types as command results instead of complex objects.
385-
If there is benefit in providing class objects designers should choose immutable over mutable types and never
384+
As a rule of thumb it is safer for the designer to return simple scalar types as command results instead of complex
385+
objects. If there is benefit in providing class objects designers should choose immutable over mutable types and never
386386
provide direct access to class members as this could potentially lead to violation of the open_closed_principle_.
387387

388-
When possible, a dataclass is a lightweight solution perfectly suited for data manipulation. Lets dive into an
388+
When possible, a dataclass is a lightweight solution perfectly suited for data manipulation. Lets dive into an
389389
example.
390390

391391
The following fictitional application has two commands: ``build`` and ``status``. We can pretend that the build action
392392
happens somewhere else in the world at an REST API endpoint and has significant computational cost. The status command
393393
for all intents and purposes will only show the current status of a build task. The application has provided all that is
394-
needed for a user to start a build and then determine it's status. The problem however is that with a long running process
395-
the user may want to wait for it to finish. A designer may be tempted to create a command to start a build and then
396-
poll for status until finished but this scenario is better solved as an extensible script.
394+
needed for a user to start a build and then determine it's status. The problem however is that with a long running
395+
process the user may want to wait for it to finish. A designer may be tempted to create a command to start a build and
396+
then poll for status until finished but this scenario is better solved as an extensible script.
397397

398398
app.py::
399399

@@ -501,7 +501,7 @@ The below is a possible solution via pyscript::
501501

502502
build_status = result.data
503503

504-
# If the status shows complete then we are done
504+
# If the status shows complete then we are done
505505
if build_status.status in ['finished', 'canceled']:
506506
print(f"Build {build.name} has completed")
507507
break
@@ -520,4 +520,4 @@ The below is a possible solution via pyscript::
520520
https://en.wikipedia.org/wiki/Unix_philosophy
521521

522522
.. _open_closed_principle:
523-
https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle
523+
https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle

tasks.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,14 @@ def format(context):
366366

367367

368368
namespace.add_task(format)
369+
370+
371+
# Ruff fast auto-formatter and linter
372+
@invoke.task()
373+
def ruff(context):
374+
"""Run ruff fast auto-formatter and linter"""
375+
with context.cd(TASK_ROOT_STR):
376+
context.run("ruff check")
377+
378+
379+
namespace.add_task(ruff)

0 commit comments

Comments
 (0)