# `zipapp` — Διαχείριση εκτελέσιμων αρχείων zip Python

Added in version 3.5.

Πηγαίος κώδικας: Lib/zipapp.py

Το παρόν module παρέχει εργαλεία για τη διαχείριση της δημιουργίας αρχείων zip που περιέχουν κώδικα Python, τα οποία μπορούν να executed directly by the Python interpreter. Το module παρέχει τόσο μια Διεπαφή Γραμμής Εντολών όσο και ένα Διεπαφή Python.

## Βασικό Παράδειγμα

Το παρακάτω παράδειγμα δείχνει πώς μπορεί να χρησιμοποιηθεί η Διεπαφή Γραμμής Εντολών για να δημιουργήσει ένα εκτελέσιμο αρχείο από έναν φάκελο που περιέχει κώδικα Python. Όταν εκτελείται, το αρχείο θα εκτελέσει τη συνάρτηση `main` από το module `myapp` στο αρχείο.

    $ python -m zipapp myapp -m "myapp:main"
    $ python myapp.pyz
    <output from myapp>

## Διεπαφή Γραμμής Εντολών

Όταν καλείται ως πρόγραμμα από τη γραμμή εντολών, χρησιμοποιείται η παρακάτω μορφή:

    $ python -m zipapp source [options]

Αν το source είναι ένας φάκελος, αυτό θα δημιουργήσει ένα αρχείο από τα περιεχόμενα του source. Αν το source είναι ένα αρχείο, θα πρέπει να είναι ένα αρχείο, και θα αντιγραφεί στο αρχείο προορισμού (ή το περιεχόμενο της γραμμής shebang θα εμφανιστεί αν έχει καθοριστεί η επιλογή –info).

Οι παρακάτω επιλογές γίνονται κατανοητές:

-o <output>, --output=<output>

  Γράφει την έξοδο σε ένα αρχείο με όνομα output. Αν αυτή η επιλογή δεν καθοριστεί, το όνομα του αρχείου εξόδου θα είναι το ίδιο με το εισαγωγικό source, με την προσθήκη της επέκτασης `.pyz`. Αν καθοριστεί ένα ρητό όνομα αρχείου, χρησιμοποιείται όπως είναι (έτσι θα πρέπει να συμπεριληφθεί μια επέκταση `.pyz` αν απαιτείται).

  Ένα όνομα αρχείου εξόδου πρέπει να καθοριστεί αν το source είναι ένα αρχείο (και σε αυτή την περίπτωση, το output δεν πρέπει να είναι το ίδιο με το source).

-p <interpreter>, --python=<interpreter>

  Προσθέτει μια γραμμή `#!` στο αρχείο που καθορίζει το interpreter ως την εντολή που θα εκτελεστεί. Επίσης, σε POSIX, καθιστά το αρχείο εκτελέσιμο. Η προεπιλογή είναι να μην γράφεται καμία γραμμή `#!` και να μην καθίσταται το αρχείο εκτελέσιμο.

-m <mainfn>, --main=<mainfn>

  Γράφει ένα αρχείο `__main__.py` στο αρχείο που εκτελεί το mainfn. Το mainfn πρέπει να έχει τη μορφή «pkg.mod:fn», όπου «pkg.mod» είναι ένα πακέτο/module στο αρχείο, και «fn» είναι μια καλούμενη συνάρτηση στο δεδομένο module. Το αρχείο `__main__.py` θα εκτελέσει αυτή τη συνάρτηση.

  Η επιλογή `--main` δεν μπορεί να καθοριστεί κατά την αντιγραφή ενός αρχείου.

-c, --compress

  Συμπιέζει τα αρχεία με τη μέθοδο deflate, μειώνοντας το μέγεθος του αρχείου εξόδου. Από προεπιλογή, τα αρχεία αποθηκεύονται χωρίς συμπίεση στο αρχείο.

  Η επιλογή `--compress` δεν έχει καμία επίδραση κατά την αντιγραφή ενός αρχείου.

  Added in version 3.7.

--info

  Εμφανίζει τον ενσωματωμένο διερμηνέα στο αρχείο, για διαγνωστικούς σκοπούς. Σε αυτή την περίπτωση, αγνοούνται όλες οι άλλες επιλογές και το SOURCE πρέπει να είναι ένα αρχείο, όχι ένας φάκελος.

-h, --help

  Εκτυπώνει ένα σύντομο μήνυμα χρήσης και εξέρχεται.

## Διεπαφή Python

Το module ορίζει δύο συναρτήσεις ευκολίας:

zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

  Δημιουργεί ένα αρχείο εφαρμογής από το source. Η πηγή μπορεί να είναι οποιοδήποτε από τα παρακάτω:

  - Το όνομα ενός φακέλου, ή ένα path-like object που αναφέρεται σε έναν φάκελο, οπότε θα δημιουργηθεί ένα νέο αρχείο εφαρμογής από το περιεχόμενο αυτού του φακέλου.

  - Το όνομα ενός υπάρχοντος αρχείου εφαρμογής, ή ένα path-like object που αναφέρεται σε ένα τέτοιο αρχείο, οπότε το αρχείο αντιγράφεται στο προορισμό (τροποποιώντας το για να αντικατοπτρίζει την τιμή που δίνεται για το όρισμα interpreter). Το όνομα του αρχείου θα πρέπει να περιλαμβάνει την επέκταση `.pyz`, αν απαιτείται.

  - Ένα αντικείμενο αρχείου ανοιχτό για ανάγνωση σε λειτουργία bytes. Το περιεχόμενο του αρχείου θα πρέπει να είναι ένα αρχείο εφαρμογής, και το αντικείμενο αρχείου θεωρείται ότι είναι τοποθετημένο στην αρχή του αρχείου.

  Το όρισμα target καθορίζει που θα γραφτεί το αποτέλεσμα του αρχείου:

  - Αν είναι το όνομα ενός αρχείου, ή ένα path-like object, το αρχείο θα γραφτεί σε αυτό το αρχείο.

  - Αν είναι ένα ανοιχτό αντικείμενο αρχείου, το αρχείο θα γραφτεί σε αυτό το αντικείμενο αρχείου, το οποίο πρέπει να είναι ανοιχτό για εγγραφή σε λειτουργία bytes.

  - Αν το όρισμα προορισμού παραλειφθεί (ή είναι `None`), η πηγή πρέπει να είναι ένας φάκελος και ο προορισμός θα είναι ένα αρχείο με το ίδιο όνομα με την πηγή, με μια επέκταση `.pyz` προστιθέμενη.

  Το όρισμα interpreter καθορίζει το όνομα του διερμηνέα Python με τον οποίο θα εκτελείται το αρχείο. Γράφεται ως μια γραμμή «shebang» στην αρχή του αρχείου. Σε POSIX, αυτό θα ερμηνευτεί από το λειτουργικό σύστημα, και σε Windows θα διαχειριστεί από τον διερμηνέα Python. Η παράλειψη του interpreter έχει ως αποτέλεσμα να μην γραφτεί καμία γραμμή shebang. Αν καθοριστεί ένας διερμηνέας, και ο προορισμός είναι ένα όνομα αρχείου, θα τεθεί το εκτελέσιμο bit του αρχείου προορισμού.

  Το όρισμα main καθορίζει το όνομα μιας καλούμενης συνάρτησης που θα χρησιμοποιηθεί ως το κύριο πρόγραμμα για το αρχείο. Μπορεί να καθοριστεί μόνο αν η πηγή είναι ένας φάκελος, και η πηγή δεν περιέχει ήδη ένα αρχείο `__main__.py`. Το όρισμα main θα πρέπει να έχει τη μορφή «pkg.module:callable» και το αρχείο θα εκτελείται με την εισαγωγή «pkg.module» και την εκτέλεση της δεδομένης καλούμενης συνάρτησης χωρίς ορίσματα. Είναι σφάλμα να παραλειφθεί το main αν η πηγή είναι ένας φάκελος και δεν περιέχει ένα αρχείο `__main__.py`, καθώς διαφορετικά το παραγόμενο αρχείο δεν θα ήταν εκτελέσιμο.

  Το προαιρετικό όρισμα filter καθορίζει μια συνάρτηση callback που περνάει ένα αντικείμενο Path που αναπαριστά το μονοπάτι του αρχείου που προστίθεται (σχετικό με τον φάκελο πηγής). Θα πρέπει να επιστρέφει `True` αν το αρχείο πρέπει να προστεθεί.

  Το προαιρετικό όρισμα compressed καθορίζει αν τα αρχεία συμπιέζονται. Αν οριστεί σε `True`, τα αρχεία στο αρχείο συμπιέζονται με τη μέθοδο deflate. Διαφορετικά, τα αρχεία αποθηκεύονται χωρίς συμπίεση. Αυτό το όρισμα δεν έχει καμία επίδραση κατά την αντιγραφή ενός υπάρχοντος αρχείου.

  Αν ένα αντικείμενο αρχείου καθοριστεί για το source ή το target, είναι ευθύνη του καλούντος να το κλείσει μετά την κλήση της create_archive.

  Κατά την αντιγραφή ενός υπάρχοντος αρχείου, τα αντικείμενα αρχείων που παρέχονται χρειάζονται μόνο τις μεθόδους `read` και `readline`, ή `write`. Όταν δημιουργείται ένα αρχείο από έναν φάκελο, αν το target είναι ένα αντικείμενο αρχείου, θα περαστεί στην κλάση `zipfile.ZipFile` και πρέπει να παρέχει τις μεθόδους που χρειάζεται αυτή η κλάση.

  Άλλαξε στην έκδοση 3.7: Προστέθηκαν οι παράμετροι filter και compressed.

zipapp.get_interpreter(archive)

  Επιστρέφει τον διερμηνέα που καθορίζεται στη γραμμή `#!` στην αρχή του αρχείου. Αν δεν υπάρχει γραμμή `#!`, επιστρέφει `None`. Το archive μπορεί να είναι ένα όνομα αρχείου ή ένα αντικείμενο που μοιάζει με αρχείο και είναι ανοιχτό για ανάγνωση σε bytes.

## Παραδείγματα

Συσκευάζει έναν φάκελο σε ένα αρχείο, και το εκτελεί.

    $ python -m zipapp myapp
    $ python myapp.pyz
    <output from myapp>

Το ίδιο μπορεί να γίνει χρησιμοποιώντας τη συνάρτηση `create_archive()`:

    >>> import zipapp
    >>> zipapp.create_archive('myapp', 'myapp.pyz')

Για να κάνετε την εφαρμογή άμεσα εκτελέσιμη σε POSIX, καθορίστε έναν διερμηνέα που θα χρησιμοποιηθεί.

    $ python -m zipapp myapp -p "/usr/bin/env python"
    $ ./myapp.pyz
    <output from myapp>

Για να αντικαταστήσετε τη γραμμή shebang σε ένα υπάρχον αρχείο, δημιουργήστε ένα τροποποιημένο αρχείο χρησιμοποιώντας τη συνάρτηση `create_archive()`:

    >>> import zipapp
    >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

Για να ενημερώσετε το αρχείο στη θέση του, κάντε την αντικατάσταση στη μνήμη χρησιμοποιώντας ένα αντικείμενο `BytesIO`, και στη συνέχεια αντικαταστήστε την πηγή. Σημειώστε ότι υπάρχει κίνδυνος κατά την αντικατάσταση ενός αρχείου στη θέση του ότι ένα σφάλμα θα οδηγήσει στην απώλεια του αρχικού αρχείου. Αυτός ο κώδικας δεν προστατεύει από τέτοια σφάλματα, αλλά ο κώδικας παραγωγής θα πρέπει να το κάνει. Επίσης, αυτή η μέθοδος θα λειτουργήσει μόνο αν το αρχείο χωράει στη μνήμη:

    >>> import zipapp
    >>> import io
    >>> temp = io.BytesIO()
    >>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
    >>> with open('myapp.pyz', 'wb') as f:
    >>>     f.write(temp.getvalue())

## Καθορισμός του Διερμηνέα

Σημειώστε ότι αν καθορίσετε έναν διερμηνέα και στη συνέχεια διανείμετε το αρχείο εφαρμογής σας, πρέπει να διασφαλίσετε ότι ο διερμηνέας που χρησιμοποιείται είναι φορητός. Ο διερμηνέας Python για Windows υποστηρίζει τις περισσότερες κοινές μορφές γραμμής `#!` POSIX, αλλά υπάρχουν και άλλα ζητήματα που πρέπει να ληφθούν υπόψη:

- Αν χρησιμοποιήσετε «/usr/bin/env python» (ή άλλες μορφές της εντολής «python», όπως «/usr/bin/python»), πρέπει να λάβετε υπόψη ότι οι χρήστες σας μπορεί να έχουν είτε Python 2 είτε Python 3 ως προεπιλογή, και να γράψετε τον κώδικά σας ώστε να λειτουργεί και στις δύο εκδόσεις.

- Αν χρησιμοποιήσετε μια ρητή έκδοση, για παράδειγμα «/usr/bin/env python3», η εφαρμογή σας δεν θα λειτουργήσει για χρήστες που δεν έχουν αυτή την έκδοση. (Αυτό μπορεί να είναι αυτό που θέλετε αν δεν έχετε κάνει τον κώδικά σας συμβατό με την Python 2).

- Δεν υπάρχει τρόπος να πείτε «python X.Y ή νεότερη», οπότε να είστε προσεκτικοί όταν χρησιμοποιείτε μια ακριβή έκδοση όπως «/usr/bin/env python3.4», καθώς θα χρειαστεί να αλλάξετε τη γραμμή shebang για χρήστες της Python 3.5, για παράδειγμα.

Συνήθως, θα πρέπει να χρησιμοποιήσετε ένα «/usr/bin/env python2» ή «/usr/bin/env python3», ανάλογα με το αν ο κώδικάς σας είναι γραμμένος για την Python 2 ή 3.

## Δημιουργία Αυτόνομων Εφαρμογών με το zipapp

Χρησιμοποιώντας το module `zipapp`, είναι δυνατό να δημιουργηθούν αυτόνομες εφαρμογές Python, οι οποίες μπορούν να διανεμηθούν σε τελικούς χρήστες που χρειάζονται μόνο να έχουν εγκατεστημένη μια κατάλληλη έκδοση της Python στο σύστημά τους. Το κλειδί για να γίνει αυτό είναι να συμπεριληφθούν όλες οι εξαρτήσεις της εφαρμογής στο αρχείο, μαζί με τον κώδικα της εφαρμογής.

Τα βήματα για τη δημιουργία ενός αυτόνομου αρχείου είναι τα εξής:

1. Δημιουργήστε την εφαρμογή σας σε έναν φάκελο όπως συνήθως, έτσι ώστε να έχετε έναν φάκελο `myapp` που περιέχει ένα αρχείο `__main__.py` και οποιονδήποτε υποστηρικτικό κώδικα εφαρμογής.

2. Εγκαταστήστε όλες τις εξαρτήσεις της εφαρμογής σας στον φάκελο `myapp`, χρησιμοποιώντας το pip:

       $ python -m pip install -r requirements.txt --target myapp

   (αυτό υποθέτει ότι έχετε τις απαιτήσεις του έργου σας σε ένα αρχείο `requirements.txt` - αν όχι, μπορείτε απλώς να καταγράψετε τις εξαρτήσεις χειροκίνητα στη γραμμή εντολών του pip).

3. Συσκευάστε την εφαρμογή χρησιμοποιώντας:

       $ python -m zipapp -p "interpreter" myapp

Αυτό θα παράγει ένα αυτόνομο εκτελέσιμο, το οποίο μπορεί να εκτελεστεί σε οποιαδήποτε μηχανή με τον κατάλληλο διερμηνέα διαθέσιμο. Δείτε Καθορισμός του Διερμηνέα για λεπτομέρειες. Μπορεί να αποσταλεί στους χρήστες ως ένα μόνο αρχείο.

Σε Unix, το αρχείο `myapp.pyz` είναι εκτελέσιμο όπως είναι. Μπορείτε να μετονομάσετε το αρχείο για να αφαιρέσετε την επέκταση `.pyz` αν προτιμάτε ένα «καθαρό» όνομα εντολής. Σε Windows, το αρχείο `myapp.pyz[w]` είναι εκτελέσιμο λόγω του γεγονότος ότι ο διερμηνέας Python καταχωρεί τις επεκτάσεις αρχείων `.pyz` και `.pyzw` κατά την εγκατάσταση.

### Προειδοποιήσεις

Αν η εφαρμογή σας εξαρτάται από ένα πακέτο που περιλαμβάνει μια επέκταση C, αυτό το πακέτο δεν μπορεί να εκτελεστεί από ένα αρχείο zip (αυτό είναι περιορισμός του λειτουργικού συστήματος, καθώς ο εκτελέσιμος κώδικας πρέπει να είναι παρών στο σύστημα αρχείων για να τον φορτώσει ο φορτωτής του λειτουργικού συστήματος). Σε αυτή την περίπτωση, μπορείτε να εξαιρέσετε αυτή την εξάρτηση από το αρχείο zip, και είτε να απαιτήσετε από τους χρήστες σας να το έχουν εγκατεστημένο, είτε να το αποστείλετε μαζί με το αρχείο zip και να προσθέσετε κώδικα στο `__main__.py` για να συμπεριλάβετε τον φάκελο που περιέχει το αποσυμπιεσμένο module στο `sys.path`. Σε αυτή την περίπτωση, θα πρέπει να διασφαλίσετε ότι θα αποστείλετε κατάλληλα δυαδικά αρχεία για την αρχιτεκτονική/αρχιτεκτονικές (και ενδεχομένως να επιλέξετε την κατάλληλη έκδοση για να προσθέσετε στο `sys.path` κατά τη διάρκεια εκτέλεσης, με βάση τη μηχανή του χρήστη).

## Η Μορφή Αρχείου Εφαρμογής Zip της Python

Η Python μπορεί να εκτελεί αρχεία zip που περιέχουν ένα αρχείο `__main__.py` από την έκδοση 2.6. Για να εκτελεστεί από την Python, ένα αρχείο εφαρμογής απλά πρέπει να είναι ένα τυπικό αρχείο zip που περιέχει ένα αρχείο `__main__.py` το οποίο θα εκτελείται ως το σημείο εισόδου για την εφαρμογή. Όπως συνήθως για οποιοδήποτε Python script, ο γονέας του script (σε αυτή την περίπτωση το αρχείο zip) θα τοποθετηθεί στο `sys.path` και έτσι περαιτέρω modules μπορούν να εισαχθούν από το αρχείο zip.

Η μορφή αρχείου zip επιτρέπει την προσθήκη αυθαίρετων δεδομένων στην αρχή ενός αρχείου zip. Η μορφή αρχείου εφαρμογής zip χρησιμοποιεί αυτή την ικανότητα για να προσθέσει μια τυπική γραμμή «shebang» POSIX στην αρχή του αρχείου (`#!/path/to/interpreter`).

Επίσημα, η μορφή αρχείου εφαρμογής zip της Python είναι επομένως:

1. Μια προαιρετική γραμμή shebang, που περιέχει τους χαρακτήρες `b'#!'` ακολουθούμενους από ένα όνομα διερμηνέα, και στη συνέχεια έναν χαρακτήρα newline (`b'\n'`). Το όνομα του διερμηνέα μπορεί να είναι οτιδήποτε αποδεκτό από την επεξεργασία «shebang» του λειτουργικού συστήματος, ή τον διερμηνέα Python σε Windows. Ο διερμηνέας θα πρέπει να κωδικοποιείται σε UTF-8 σε Windows, και σε `sys.getfilesystemencoding()` σε POSIX.

2. Τυπικά δεδομένα αρχείου zip, όπως παράγονται από το module `zipfile`. Το περιεχόμενο του αρχείου zip πρέπει να περιλαμβάνει ένα αρχείο `__main__.py` (το οποίο πρέπει να βρίσκεται στο «root» του αρχείου zip - δηλαδή, δεν μπορεί να βρίσκεται σε υποφάκελο). Τα δεδομένα του αρχείου zip μπορεί να είναι συμπιεσμένα ή μη συμπιεσμένα.

Αν ένα αρχείο εφαρμογής έχει μια γραμμή shebang, μπορεί να έχει ρυθμιστεί το εκτελέσιμο bit σε συστήματα POSIX, για να επιτρέπεται η άμεση εκτέλεσή του.

Δεν υπάρχει απαίτηση να χρησιμοποιούνται τα εργαλεία σε αυτό το module για τη δημιουργία αρχείων εφαρμογής - το module είναι μια ευκολία, αλλά τα αρχεία σε παραπάνω μορφή που δημιουργούνται με οποιονδήποτε τρόπο είναι αποδεκτά από την Python.