Skip to content

Commit f8b6e51

Browse files
authored
Merge pull request #1 from marcofarina/fix/pyrunner-security
2 parents 95b4d2b + 3f57aab commit f8b6e51

61 files changed

Lines changed: 3559 additions & 1695 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/basi-del-linguaggio/input.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ variabile = input("Messaggio per l'utente: ")
1616

1717
### Esempio
1818

19-
```py live_py
19+
```py live
2020
name = input("Come ti chiami? ")
2121
print(f"Ciao, {name}!")
2222
```
@@ -44,15 +44,15 @@ Se si inserisce un valore non valido per la conversione (ad esempio, testo anzic
4444

4545
### Esempio con numeri interi:
4646

47-
```py live_py
47+
```py live
4848
age = input("Quanti anni hai? ")
4949
year_of_birth = 2025 - int(age) # Converte la stringa in un intero
5050
print(f"Sei nato nell'anno {year_of_birth}.")
5151
```
5252

5353
### Esempio con numeri decimali:
5454

55-
```py live_py
55+
```py live
5656
height = input("Qual è la tua altezza in metri? ")
5757
height = float(height) # Converte la stringa in un numero decimale
5858
print(f"La tua altezza in centimetri è {height * 100}.")

docs/basi-del-linguaggio/le-stringhe.mdx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ hacker = "Kevin \"Condor\" Mitnick"
2424
## Unire più stringhe: la concatenazione
2525
La **concatenazione** di stringhe è una pratica comune in programmazione e consiste nell'unire due o più stringhe per formarne una più lunga. Questa operazione è utile quando si desidera costruire un messaggio o una frase combinando parti di testo. Python offre diverse modalità per eseguire la concatenazione, una delle quali è l'utilizzo dell'operatore `+`. Ecco un esempio:
2626

27-
```py live_py
27+
```py live
2828
# Esempio di concatenazione di stringhe
2929
greeting = "It's-a me"
3030
name = "Mario"
@@ -33,7 +33,7 @@ print(message)
3333
```
3434

3535
Oltre all'operatore `+`, in alcune occasioni può essere utile l'operatore `*`, che consente di ripetere una stringa un certo numero di volte. Ad esempio:
36-
```py live_py
36+
```py live
3737
lol = "😂" * 10
3838
print(lol)
3939
```
@@ -49,7 +49,7 @@ f"Testo normale {espressione} altro testo"
4949
```
5050
Dove `{espressione}` può essere sostituito con qualsiasi espressione Python valida, comprese variabili, operazioni, chiamate di funzioni, ecc.
5151

52-
```py live_py
52+
```py live
5353
name1 = "Tony"
5454
name2 = "Steve"
5555
message = f"{name1} and {name2} are BFFs"
@@ -64,7 +64,7 @@ In Python, come in molti altri linguaggi di programmazione, gli indici delle seq
6464
:::
6565

6666
La sintassi per accedere a un carattere di una stringa è `stringa[indice]`. Ad esempio:
67-
```py live_py
67+
```py live
6868
name = "Luigi"
6969
first_letter = name[0]
7070
print(first_letter)
@@ -77,7 +77,7 @@ Vediamo di seguito alcune delle più utili e comuni.
7777

7878
### `len()`
7979
La funzione `len(stringa)` restituisce la lunghezza di una stringa, ovvero il numero di caratteri che la compongono. Ad esempio:
80-
```py live_py
80+
```py live
8181
motto = "supercalifragilistichespiralidoso"
8282
print(f"{motto} ha {len(motto)} caratteri")
8383
```
@@ -87,14 +87,14 @@ A differenza degli altri metodi, `len()` è una funzione propria di Python e non
8787

8888
### `upper()` e `lower()`
8989
Le funzioni `upper()` e `lower()`, che al contrario di `len()` sono funzioni specifiche delle stringhe, permettono di convertire una stringa in maiuscolo o minuscolo rispettivamente. Ad esempio:
90-
```py live_py
90+
```py live
9191
message = "A vEry sTrAnge mEsSaGe"
9292
print(f"'{message.upper()}' is the same as '{message.lower()}'")
9393
```
9494

9595
### `replace()`
9696
La funzione `replace(old, new)` serve a rimpiazzare una parte di una stringa con un'altra. Questa funzione ha una particolarità: riceve in input due parametri e non uno solo. I parametri vanno elencati separandoli con una virgola. Il parametro `old` rappresenta la parte della stringa da cercare e sostituire, mentre `new` rappresenta la parte di stringa nuova. Ad esempio:
97-
```py live_py
97+
```py live
9898
name = "Mario"
9999
print(name.replace("M", "W"))
100100
```

docs/basi-del-linguaggio/le-variabili.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ condizione = True # tipo bool
9696

9797
Se vuoi conoscere il tipo di una variabile, puoi usare la funzione `type()`:
9898

99-
```py live_py
99+
```py live
100100
esempio1 = 10
101101
esempio2 = "10"
102102
print(type(esempio1))
103103
print(type(esempio2))
104104
```
105105

106106
Conoscere il tipo di una variabile è importante perché determina le operazioni che possono essere eseguite su quella variabile. Osserva il seguente esempio:
107-
```py live_py
107+
```py live
108108
esempio1 = 10
109109
esempio2 = "10"
110110
print(esempio1 * 10)

docs/basi-del-linguaggio/output.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Avrai notato la prima riga nel codice qui sopra: è un **commento**. In Python,
2626
### Prova tu
2727
All'interno di questo libro troverai spesso esempi di codice che potrai eseguire direttamente nel tuo browser. Prova a completare il codice qui sotto per visualizzare il tuo primo output in Python.
2828

29-
```py live_py
29+
```py live
3030
# Completa il codice per stampare il tuo nome
3131
print("Benvenuti al corso di Python!")
3232
print()
@@ -41,7 +41,7 @@ Il comando `print()` accetta un parametro opzionale chiamato `end`, che consente
4141

4242
Prova a eseguire il codice: cosa succede se modifichi il valore del parametro `end`?
4343

44-
```py live_py
44+
```py live
4545
print("1", end=", ")
4646
print("2", end=", ")
4747
print("3")

docs/pyrunner-test.mdx

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
unlisted: true
3+
title: PyRunner — pagina di test
4+
description: Sandbox di verifica del componente PyRunner (PR1)
5+
---
6+
7+
# PyRunner — sandbox di test
8+
9+
Pagina temporanea per validare la PR1 del nuovo PyRunner. Non è linkata dalla sidebar (`unlisted: true`).
10+
11+
## 1. Fence inline `py live` — esempio base
12+
13+
```py live
14+
nome = "Lia"
15+
print(f"Ciao, {nome}!")
16+
print("Questo è il primo esempio.")
17+
```
18+
19+
## 2. Da file `.py` esterno
20+
21+
import PyRunner from '@theme/PyRunner';
22+
23+
<PyRunner src="_test/hello.py" />
24+
25+
## 3. File `.py` con `### PRE` / `### POST`
26+
27+
Il blocco `PRE` definisce `risultato_atteso`, il blocco `POST` non c'è. Solo il corpo è visibile/editabile.
28+
29+
<PyRunner src="_test/somma.py" title="Test PRE/POST" />
30+
31+
## 4. Fence con errore runtime (deve mostrare stderr in rosso)
32+
33+
```py live
34+
def dividi(a, b):
35+
return a / b
36+
37+
print(dividi(10, 2))
38+
print(dividi(5, 0)) # ZeroDivisionError
39+
```
40+
41+
## 5. Snippet a una riga (no line numbers attesi)
42+
43+
```py live
44+
print("Una riga sola, niente gutter.")
45+
```
46+
47+
## 6. Readonly
48+
49+
```py live readonly
50+
# Questo non si edita.
51+
for i in range(3):
52+
print(f"iterazione {i}")
53+
```
54+
55+
## 7. maxLines piccolo per forzare scroll interno
56+
57+
`maxLines=5` limita l'altezza dell'editor: il codice qui ha ~15 righe, quindi
58+
deve comparire una scrollbar verticale interna al box, senza espandere la pagina.
59+
Quando l'editor scrolla, deve comparire anche il bottone _fullscreen_ in toolbar.
60+
61+
```py live maxLines=5
62+
def saluta(nome):
63+
print(f"Ciao, {nome}!")
64+
65+
def somma(a, b):
66+
return a + b
67+
68+
def fattoriale(n):
69+
if n <= 1:
70+
return 1
71+
return n * fattoriale(n - 1)
72+
73+
saluta("Lia")
74+
saluta("Marco")
75+
print("2 + 3 =", somma(2, 3))
76+
print("5! =", fattoriale(5))
77+
```
78+
79+
## 8. "Spiegamelo facile" — prompt di default
80+
81+
Cliccando l'icona ✨ in toolbar viene copiato negli appunti un prompt didattico
82+
che usa il titolo di questa pagina come `{contextTitle}` e il codice corrente
83+
(edit-aware).
84+
85+
```py live
86+
parola = "ciao"
87+
print(parola.upper())
88+
print(parola[::-1])
89+
```
90+
91+
## 9. "Spiegamelo facile" con prompt custom
92+
93+
```py live
94+
n = 5
95+
print(sum(range(n + 1)))
96+
```
97+
98+
import PyRunnerCustom from '@theme/PyRunner';
99+
100+
<PyRunnerCustom
101+
code={`# Lezione sulle list comprehension
102+
quadrati = [x * x for x in range(5)]
103+
print(quadrati)`}
104+
explainPrompt={`Sto imparando le list comprehension in Python. Spiega il codice qui sotto in 3 frasi, in italiano, indicando come si tradurrebbe nello stesso codice scritto con un ciclo \`for\` esplicito.\n\nCodice:\n\`\`\`python\n{code}\n\`\`\`\n`}
105+
/>
106+
107+
## 10. `noExplain` — niente icona spiega
108+
109+
```py live noExplain
110+
print("Niente bottone bacchetta magica qui.")
111+
```
112+
113+
## 11. Fullscreen forzato (`maxLines=3` per attivare overflow)
114+
115+
```py live maxLines=3
116+
print("Riga 1")
117+
print("Riga 2")
118+
print("Riga 3")
119+
print("Riga 4")
120+
print("Riga 5")
121+
```

docusaurus.config.ts

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { themes as prismThemes } from 'prism-react-renderer';
22
import type { Config } from '@docusaurus/types';
33
import type * as Preset from '@docusaurus/preset-classic';
44

5+
// eslint-disable-next-line @typescript-eslint/no-require-imports
6+
const remarkPyRunner = require('./plugins/pyrunner/remark.js');
7+
58
const config: Config = {
69
title: 'Python Doesn\'t Byte',
710
tagline: 'Il libro di testo, reinventato.',
@@ -45,6 +48,7 @@ const config: Config = {
4548
// Please change this to your repo.
4649
// Remove this to remove the "edit this page" links.
4750
editUrl: 'https://github.com/marcofarina/python-doesnt-byte',
51+
beforeDefaultRemarkPlugins: [remarkPyRunner],
4852
},
4953
blog: {
5054
showReadingTime: true,
@@ -77,6 +81,54 @@ const config: Config = {
7781

7882
clientModules: ['./src/fonts.ts'],
7983

84+
plugins: [
85+
'./plugins/pyrunner/index.js',
86+
[
87+
'@docusaurus/plugin-content-docs',
88+
{
89+
id: 'programmatore',
90+
path: 'volumes/programmatore',
91+
routeBasePath: 'programmatore',
92+
sidebarPath: './sidebars/programmatore.ts',
93+
editUrl: 'https://github.com/marcofarina/python-doesnt-byte',
94+
beforeDefaultRemarkPlugins: [remarkPyRunner],
95+
},
96+
],
97+
[
98+
'@docusaurus/plugin-content-docs',
99+
{
100+
id: 'artefice',
101+
path: 'volumes/artefice',
102+
routeBasePath: 'artefice',
103+
sidebarPath: './sidebars/artefice.ts',
104+
editUrl: 'https://github.com/marcofarina/python-doesnt-byte',
105+
beforeDefaultRemarkPlugins: [remarkPyRunner],
106+
},
107+
],
108+
[
109+
'@docusaurus/plugin-content-docs',
110+
{
111+
id: 'archivista',
112+
path: 'volumes/archivista',
113+
routeBasePath: 'archivista',
114+
sidebarPath: './sidebars/archivista.ts',
115+
editUrl: 'https://github.com/marcofarina/python-doesnt-byte',
116+
beforeDefaultRemarkPlugins: [remarkPyRunner],
117+
},
118+
],
119+
[
120+
'@docusaurus/plugin-content-docs',
121+
{
122+
id: 'apprendista',
123+
path: 'volumes/apprendista',
124+
routeBasePath: 'apprendista',
125+
sidebarPath: './sidebars/apprendista.ts',
126+
editUrl: 'https://github.com/marcofarina/python-doesnt-byte',
127+
beforeDefaultRemarkPlugins: [remarkPyRunner],
128+
},
129+
],
130+
],
131+
80132
themeConfig: {
81133
// Replace with your project's social card
82134
image: 'img/docusaurus-social-card.jpg',
@@ -93,36 +145,43 @@ const config: Config = {
93145
},
94146
items: [
95147
{
96-
type: 'docSidebar',
97-
sidebarId: 'docs',
148+
type: 'dropdown',
149+
label: 'Libri',
98150
position: 'left',
99-
label: 'Libro',
151+
items: [
152+
{
153+
type: 'doc',
154+
docId: 'intro',
155+
docsPluginId: 'programmatore',
156+
label: 'Manuale del Programmatore',
157+
},
158+
{
159+
type: 'doc',
160+
docId: 'intro',
161+
docsPluginId: 'artefice',
162+
label: 'Manuale dell\'Artefice',
163+
},
164+
{
165+
type: 'doc',
166+
docId: 'intro',
167+
docsPluginId: 'archivista',
168+
label: 'Manuale dell\'Archivista',
169+
},
170+
{
171+
type: 'doc',
172+
docId: 'intro',
173+
docsPluginId: 'apprendista',
174+
label: 'Biblioteca dell\'Apprendista',
175+
},
176+
],
100177
},
101178
/* {
102179
to: '/blog',
103180
label: 'Blog',
104181
position: 'left'},*/
105-
{
106-
to: '/support/',
107-
label: 'Support',
108-
position: 'right',
109-
className: 'sponsorship-link',
110-
},
111-
{
112-
to: 'https://github.com/marcofarina/python-doesnt-byte',
113-
label: 'GitHub',
114-
position: 'right',
115-
target: '_blank',
116-
className: 'github-link',
117-
'aria-label': 'GitHub repository',
118-
},
119-
{
120-
to: 'https://www.rainbowbits.cloud',
121-
label: 'Rainbow Bits',
122-
position: 'right',
123-
target: '_blank',
124-
className: 'rainbowbits-link',
125-
},
182+
// GitHub e "Offrimi un caffè" sono renderizzati come icone+popup
183+
// (NavbarIconButton) dal swizzle src/theme/Navbar/Content, non
184+
// tramite navbar items standard.
126185
],
127186
},
128187
footer: {
@@ -172,9 +231,6 @@ const config: Config = {
172231
darkTheme: prismThemes.dracula,
173232
},
174233
} satisfies Preset.ThemeConfig,
175-
themes: [
176-
'docusaurus-live-brython'
177-
],
178234
};
179235

180236
export default config;

0 commit comments

Comments
 (0)