"annotationlib" --- Λειτουργικότητα για την ενδοσκόπηση των επισημάνσεων (annotations)
**************************************************************************************

Added in version 3.14.

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

======================================================================

Το module "annotationlib" παρέχει εργαλεία για την ενδοσκόπηση των
*annotations* σε modules, κλάσεις και συναρτήσεις.

Οι επισημάνσεις (annotations) αξιολογούνται νωχελικά και συχνά
περιέχουν αναφορές προς τα εμπρός σε αντικείμενα που δεν έχουν ακόμη
οριστεί όταν δημιουργείται η επισήμανση (annotation). Αυτό το module
παρέχει ένα σύνολο εργαλείων χαμηλού επιπέδου, που μπορούν να
χρησιμοποιηθούν για την αξιόπιστη ανάκτηση των επισημάνσεων
(annotations), ακόμη και στην παρουσία αναφορών προς τα εμπρός και
άλλων ακραίων περιπτώσεων.

Αυτό το module υποστηρίζει την ανάκτηση των επισημάνσεων (annotations)
σε τρεις κύριες μορφές (δείτε το "Format"), κάθε μία από τις οποίες
λειτουργεί καλύτερα για διαφορετικές περιπτώσεις χρήσης:

* Το "VALUE" αξιολογεί τις επισημάνσεις (annotations) και επιστρέφει
  την τιμή τους. Αυτή είναι η πιο απλή μορφή για να εργαστεί κανείς,
  αλλά μπορεί να εγείρει σφάλματα, για παράδειγμα αν οι επισημάνσεις
  (annotations) περιέχουν αναφορές σε ονόματα που δεν έχουν οριστεί.

* Το "FORWARDREF" επιστρέφει αντικείμενα "ForwardRef" για
  επισημάνσεις (annotations) που δεν μπορούν να επιλυθούν,
  επιτρέποντάς σας να επιθεωρήσετε τις επισημάνσεις (annotations)
  χωρίς να τα αξιολογήσετε. Αυτό είναι χρήσιμο όταν χρειάζεται να
  εργαστείτε με επισημάνσεις (annotations) που μπορεί να περιέχουν
  ανεπίλυτες αναφορές προς τα εμπρός.

* Το "STRING" επιστρέφει τις επισημάνσεις (annotations) ως
  συμβολοσειρά, ομοίως με τον τρόπο που θα εμφανίζονταν στο αρχείο του
  πηγαίου κώδικα. Αυτό είναι χρήσιμο για γεννήτριες τεκμηρίωσης που
  θέλουν να εμφανίζουν τις επισημάνσεις (annotations) με αναγνώσιμο
  τρόπο.

Η συνάρτηση "get_annotations()" είναι το κύριο σημείο εισόδου για την
ανάκτηση των επισημάνσεων (annotations). Δοθείσας μιας συνάρτησης,
μιας κλάσης ή ενός module, επιστρέφει ένα λεξικό των επισημάνσεων
(annotations) στη ζητούμενη μορφή. Αυτό το module παρέχει επίσης τη
λειτουργικότητα για την άμεση εργασία με την *annotate function*, που
χρησιμοποιείται για την αξιολόγηση των επισημάνσεων (annotations),
όπως οι "get_annotate_from_class_namespace()" και
"call_annotate_function()", καθώς και τη συνάρτηση
"call_evaluate_function()" για εργασία με *evaluate functions*.

Προσοχή:

  Η περισσότερη λειτουργικότητα σε αυτό το module μπορεί να εκτελέσει
  αυθαίρετο κώδικα· δείτε την ενότητα ασφαλείας για περισσότερες
  πληροφορίες.

Δείτε επίσης:

  Το **PEP 649** πρότεινε το τρέχον μοντέλο για το πώς λειτουργούν οι
  επισημάνσεις (annotations) στην Python.

  Το **PEP 749** επέκτεινε διάφορες πτυχές του **PEP 649** και
  εισήγαγε το module "annotationlib".

  Το Annotations Best Practices παρέχει βέλτιστες πρακτικές για την
  εργασία με τις επισημάνσεις (annotations).

  Το typing-extensions παρέχει ένα backport της "get_annotations()"
  που λειτουργεί σε προγενέστερες εκδόσεις της Python.


Σημασιολογία των επισημάνσεων (annotations)
===========================================

Ο τρόπος αξιολόγησης των επισημάνσεων (annotations) έχει αλλάξει κατά
τη διάρκεια της ιστορίας της Python 3 και επί του παρόντος εξαρτάται
ακόμα από μια εισαγωγή future. Υπήρξαν μοντέλα εκτέλεσης για τις
επισημάνσεις (annotations):

* *Βασική σημασιολογία* (προεπιλογή στην Python από την έκδοση 3.0 έως
  την 3.13· δείτε τα **PEP 3107** και **PEP 526**): οι επισημάνσεις
  (annotations) αξιολογούνται άμεσα, όπως συναντώνται στον πηγαίο
  κώδικα.

* *Επισημάνσεις (annotations) ως συμβολοσειρές* (χρησιμοποιούνται με
  το "from __future__ import annotations" από την Python 3.7 και μετά·
  δείτε το **PEP 563**): οι επισημάνσεις (annotations) αποθηκεύονται
  μόνο ως συμβολοσειρές.

* *Αναβαλλόμενη αξιολόγηση* (προεπιλογή από την Python 3.14 και μετά·
  δείτε τα **PEP 649** και **PEP 749**): οι επισημάνσεις (annotations)
  αξιολογούνται νωχελικά, μόνο όταν προσπελαύνονται.

Ως παράδειγμα, εξετάστε το ακόλουθο πρόγραμμα:

   def func(a: Cls) -> None:
       print(a)

   class Cls: pass

   print(func.__annotations__)

Αυτό θα συμπεριφερθεί ως εξής:

* Υπό τη βασική σημασιολογία (Python 3.13 και προγενέστερες), θα
  εγείρει ένα "NameError" στη γραμμή όπου ορίζεται η "func", επειδή το
  "Cls" είναι ένα μη ορισμένο όνομα σε εκείνο το σημείο.

* Υπό τις επισημάνσεις (annotations) ως συμβολοσειρές (αν
  χρησιμοποιείται το "from __future__ import annotations"), θα
  εκτυπώσει "{'a': 'Cls', 'return': 'None'}".

* Υπό την αναβαλλόμενη αξιολόγηση (Python 3.14 και μεταγενέστερες), θα
  εκτυπώσει "{'a': <class 'Cls'>, 'return': None}".

Η βασική σημασιολογία χρησιμοποιήθηκε όταν οι επισημάνσεις
(annotations) συναρτήσεων εισήχθησαν για πρώτη φορά στην Python 3.0
(από το **PEP 3107**), επειδή ήταν ο απλούστερος, πιο προφανής τρόπος
υλοποίησης των επισημάνσεων (annotations). Το ίδιο μοντέλο εκτέλεσης
χρησιμοποιήθηκε όταν εισήχθησαν οι επισημάνσεις (annotations)
μεταβλητών στην Python 3.6 (από το **PEP 526**). Ωστόσο, η βασική
σημασιολογία προκάλεσε προβλήματα κατά τη χρήση των επισημάνσεων
(annotations) ως υποδείξεων τύπων, όπως η ανάγκη αναφοράς σε ονόματα
που δεν έχουν ακόμη οριστεί όταν συναντάται η επισήμανση. Επιπλέον,
υπήρξαν προβλήματα απόδοσης με την εκτέλεση των επισημάνσεων
(annotations) κατά τον χρόνο εισαγωγής του module. Επομένως, στην
Python 3.7, το **PEP 563** εισήγαγε τη δυνατότητα αποθήκευσης των
επισημάνσεων (annotations) ως συμβολοσειρές χρησιμοποιώντας τη σύνταξη
"from __future__ import annotations". Το σχέδιο τότε ήταν να γίνει
τελικά αυτή η συμπεριφορά η προεπιλογή, αλλά εμφανίστηκε ένα πρόβλημα:
οι επισημάνσεις (annotations) ως συμβολοσειρές είναι πιο δύσκολο να
επεξεργαστούν για όσα άτομα κάνουν ενδοσκόπηση στις επισημάνσεις
(annotations) κατά τον χρόνο εκτέλεσης. Σαν εναλλακτική πρόταση, το
**PEP 649**, εισήγαγε το τρίτο μοντέλο εκτέλεσης, την αναβαλλόμενη
αξιολόγηση, και υλοποιήθηκε στην Python 3.14. Οι επισημάνσεις
(annotations) ως συμβολοσειρές εξακολουθούν να χρησιμοποιούνται αν
υπάρχει το "from __future__ import annotations", αλλά αυτή η
συμπεριφορά θα αφαιρεθεί τελικά.


Κλάσεις
=======

class annotationlib.Format

   Μία "IntEnum" που περιγράφει τις μορφές στις οποίες μπορούν να
   επιστραφούν οι επισημάνσεις (annotations). Τα μέλη του enum, ή οι
   ισοδύναμες ακέραιες τιμές τους, μπορούν να περαστούν στη
   "get_annotations()" και σε άλλες συναρτήσεις αυτού του module,
   καθώς και σε συναρτήσεις "__annotate__".

   VALUE = 1

      Οι τιμές είναι το αποτέλεσμα της αξιολόγησης των εκφράσεων
      σχολιασμού.

   VALUE_WITH_FAKE_GLOBALS = 2

      Ειδική τιμή που χρησιμοποιείται για να σηματοδοτήσει ότι μια
      συνάρτηση σχολιασμού αξιολογείται σε ένα ειδικό περιβάλλον με
      ψεύτικα καθολικά (fake globals). Όταν περνιέται αυτή η τιμή, οι
      συναρτήσεις σχολιασμού θα πρέπει είτε να επιστρέψουν την ίδια
      τιμή όπως για τη μορφή "Format.VALUE", είτε να εγείρουν
      "NotImplementedError" για να σηματοδοτήσουν ότι δεν υποστηρίζουν
      εκτέλεση σε αυτό το περιβάλλον. Αυτή η μορφή χρησιμοποιείται
      μόνο εσωτερικά και δεν πρέπει να περνιέται στις συναρτήσεις
      αυτού του module.

   FORWARDREF = 3

      Οι τιμές είναι πραγματικές τιμές σχολιασμού (όπως στη μορφή
      "Format.VALUE") για ορισμένες τιμές, και αντιπρόσωποι (proxies)
      "ForwardRef" για μη ορισμένες τιμές. Τα πραγματικά αντικείμενα
      μπορεί να περιέχουν αναφορές σε αντικείμενα αντιπροσώπων
      "ForwardRef".

   STRING = 4

      Οι τιμές είναι η συμβολοσειρά κειμένου της επισήμανσης
      (annotation) όπως εμφανίζεται στον πηγαίο κώδικα, με κάποιες
      τροποποιήσεις που περιλαμβάνουν κανονικοποιήσεις λευκών
      χαρακτήρων και βελτιστοποιήσεις σταθερών τιμών (αλλά δεν
      περιορίζονται σε αυτές).

      Οι ακριβείς τιμές αυτών των συμβολοσειρών ενδέχεται να αλλάξουν
      σε μελλοντικές εκδόσεις της Python.

   Added in version 3.14.

class annotationlib.ForwardRef

   Ένα αντικείμενο αντιπροσώπου για αναφορές προς τα εμπρός σε
   επισημάνσεις (annotations).

   Στιγμιότυπα αυτής της κλάσης επιστρέφονται όταν χρησιμοποιείται η
   μορφή "FORWARDREF" και οι επισημάνσεις (annotations) περιέχουν ένα
   όνομα που δεν μπορεί να επιλυθεί. Αυτό μπορεί να συμβεί όταν
   χρησιμοποιείται μια αναφορά προς τα εμπρός σε μια επισήμανση
   (annotation), όπως όταν γίνεται αναφορά σε μια κλάση πριν αυτή
   οριστεί.

   __forward_arg__

      Μια συμβολοσειρά που περιέχει τον κώδικα που αξιολογήθηκε για να
      παραχθεί η "ForwardRef". Η συμβολοσειρά μπορεί να μην είναι
      ακριβώς ισοδύναμη με τον αρχικό πηγαίο κώδικα.

   evaluate(*, owner=None, globals=None, locals=None, type_params=None, format=Format.VALUE)

      Αξιολογεί την αναφορά προς τα εμπρός, επιστρέφοντας την τιμή
      της.

      Αν το όρισμα *format* είναι "VALUE" (η προεπιλογή), αυτή η
      μέθοδος μπορεί να προκαλέσει μια εξαίρεση, όπως την "NameError",
      αν η αναφορά προς τα εμπρός αναφέρεται σε ένα όνομα που δεν
      μπορεί να επιλυθεί. Τα ορίσματα αυτής της μεθόδου μπορούν να
      χρησιμοποιηθούν για να παρέχουν συνδέσεις για ονόματα που
      διαφορετικά θα ήταν μη ορισμένα. Αν το όρισμα *format* είναι
      "FORWARDREF", η μέθοδος δεν θα προκαλέσει ποτέ εξαίρεση, αλλά
      μπορεί να επιστρέψει ένα στιγμιότυπο της "ForwardRef". Για
      παράδειγμα, αν το αντικείμενο αναφοράς προς τα εμπρός περιέχει
      τον κώδικα "list[undefined]", όπου "undefined" είναι ένα όνομα
      που δεν έχει οριστεί, η αξιολόγησή του με τη μορφή "FORWARDREF"
      θα επιστρέψει "list[ForwardRef('undefined')]". Αν το όρισμα
      *format* είναι "STRING", η μέθοδος θα επιστρέψει
      "__forward_arg__".

      Η παράμετρος *owner* παρέχει τον προτιμώμενο μηχανισμό για το
      πέρασμα πληροφοριών εμβέλειας σε αυτή τη μέθοδο. Ο ιδιοκτήτης
      μιας "ForwardRef" είναι το αντικείμενο που περιέχει τον
      σχολιασμό από τον οποίο προέρχεται η "ForwardRef", όπως ένα
      αντικείμενο module, αντικείμενο τύπου ή αντικείμενο συνάρτησης.

      Οι παράμετροι *globals*, *locals* και *type_params* παρέχουν
      έναν πιο ακριβή μηχανισμό για τον επηρεασμό των ονομάτων που
      είναι διαθέσιμα όταν αξιολογείται η "ForwardRef". Τα *globals*
      και *locals* περνιούνται στη "eval()", αντιπροσωπεύοντας τους
      καθολικούς και τοπικούς χώρους ονομάτων στους οποίους
      αξιολογείται το όνομα. Η παράμετρος *type_params* είναι σχετική
      για αντικείμενα που δημιουργούνται χρησιμοποιώντας την εγγενή
      σύνταξη για γενικευμένες κλάσεις και συναρτήσεις. Είναι ένα
      tuple από παραμέτρους τύπου που είναι εντός εμβέλειας όσο η
      αναφορά προς τα εμπρός αξιολογείται. Για παράδειγμα, αν
      αξιολογείται μία "ForwardRef" που ανακτήθηκε από έναν μια
      επισήμανση (annotation), που βρίσκεται στον χώρο ονομάτων κλάσης
      μιας γενικευμένης κλάσης "C", το *type_params* θα πρέπει να
      οριστεί ως "C.__type_params__".

      Τα στιγμιότυπα "ForwardRef" που επιστρέφονται από τη
      "get_annotations()" διατηρούν αναφορές σε πληροφορίες σχετικές
      με την εμβέλεια από την οποία προήλθαν, οπότε η κλήση αυτής της
      μεθόδου χωρίς περαιτέρω ορίσματα μπορεί να είναι επαρκής για την
      αξιολόγηση τέτοιων αντικειμένων. Τα στιγμιότυπα της "ForwardRef"
      που δημιουργούνται με άλλα μέσα μπορεί να μην έχουν καμία
      πληροφορία σχετικά με την εμβέλειά τους, οπότε το πέρασμα
      ορισμάτων σε αυτή τη μέθοδο μπορεί να είναι απαραίτητο για την
      επιτυχή αξιολόγησή τους.

      Αν δεν παρέχεται κανένα από τα *owner*, *globals*, *locals* ή
      *type_params* και η "ForwardRef" δεν περιέχει πληροφορίες
      σχετικά με την προέλευσή της, χρησιμοποιούνται κενά καθολικά και
      τοπικά λεξικά.

   Added in version 3.14.


Συναρτήσεις
===========

annotationlib.annotations_to_string(annotations)

   Μετατρέπει ένα λεξικό επισημάνσεων (annotations) που περιέχει τιμές
   χρόνου εκτέλεσης, σε ένα λεξικό που περιέχει μόνο συμβολοσειρές. Αν
   οι τιμές δεν είναι ήδη συμβολοσειρές, μετατρέπονται χρησιμοποιώντας
   τη "type_repr()". Αυτό προορίζεται ως βοηθητικό εργαλείο για
   συναρτήσεις annotate, που παρέχονται από τον χρήστη και
   υποστηρίζουν τη μορφή "STRING" αλλά δεν έχουν πρόσβαση στον κώδικα
   που δημιουργεί τις επισημάνσεις (annotations).

   For example, this is used to implement the "STRING" format for
   "typing.TypedDict" classes created through the functional syntax:

      >>> from typing import TypedDict
      >>> Movie = TypedDict("movie", {"name": str, "year": int})
      >>> get_annotations(Movie, format=Format.STRING)
      {'name': 'str', 'year': 'int'}

   Added in version 3.14.

annotationlib.call_annotate_function(annotate, format, *, owner=None)

   Καλεί τη *συνάρτηση σχολιασμού* *annotate* με το δοθέν *format*,
   ένα μέλος του enum "Format", και επιστρέφει το λεξικό των
   επισημάνσεων (annotations) που παράγεται από τη συνάρτηση.

   Αυτή η βοηθητική συνάρτηση απαιτείται, επειδή οι συναρτήσεις
   annotate που δημιουργούνται από τον μεταγλωττιστή για τις
   συναρτήσεις, τις κλάσεις και τα modules υποστηρίζουν μόνο τη μορφή
   "VALUE", όταν καλούνται απευθείας. Για την υποστήριξη άλλων μορφών,
   αυτή η συνάρτηση καλεί τη συνάρτηση annotate σε ένα ειδικό
   περιβάλλον που της επιτρέπει να παράγει επισημάνσεις (annotations)
   στις άλλες μορφές. Αυτό είναι ένα χρήσιμο δομικό στοιχείο κατά την
   υλοποίηση λειτουργικότητας, που χρειάζεται να αξιολογεί μερικώς τις
   επισημάνσεις (annotations) ενώ κατασκευάζεται μια κλάση.

   Το *owner* είναι το αντικείμενο που κατέχει τη συνάρτηση annotate,
   συνήθως μια συνάρτηση, κλάση ή module. Αν παρέχεται,
   χρησιμοποιείται στη μορφή "FORWARDREF" για να παράγει ένα
   αντικείμενο της "ForwardRef" που μεταφέρει περισσότερες
   πληροφορίες.

   Δείτε επίσης:

     Το **PEP 649** περιέχει μια εξήγηση της τεχνικής υλοποίησης που
     χρησιμοποιείται από αυτή τη συνάρτηση.

   Added in version 3.14.

annotationlib.call_evaluate_function(evaluate, format, *, owner=None)

   Καλεί τη *συνάρτηση αξιολόγησης* *evaluate* με ο δοθέν *format*,
   ένα μέλος του enum "Format", και επιστρέφει την τιμή που παράγεται
   από τη συνάρτηση. Είναι παρόμοιο με την "call_annotate_function()",
   αλλά η τελευταία επιστρέφει πάντα ένα λεξικό που αντιστοιχίζει
   συμβολοσειρές σε επισημάνσεις (annotations), ενώ αυτή η συνάρτηση
   επιστρέφει μια ενιαία τιμή.

   Προορίζεται για χρήση με τις συναρτήσεις αξιολόγησης που
   δημιουργούνται για νωχελικά αξιολογούμενα στοιχεία, που σχετίζονται
   με ψευδώνυμα τύπων και παραμέτρους τύπου:

   * "typing.TypeAliasType.evaluate_value()", η τιμή των ψευδωνύμων
     τύπων

   * "typing.TypeVar.evaluate_bound()", το όριο των μεταβλητών τύπου

   * "typing.TypeVar.evaluate_constraints()", οι περιορισμοί των
     μεταβλητών τύπου

   * "typing.TypeVar.evaluate_default()", η προεπιλεγμένη τιμή των
     μεταβλητών τύπου

   * "typing.ParamSpec.evaluate_default()", η προεπιλεγμένη τιμή των
     προδιαγραφών παραμέτρων

   * "typing.TypeVarTuple.evaluate_default()", η προεπιλεγμένη τιμή
     των μεταβλητών τύπου tuple

   Το *owner* είναι το αντικείμενο που κατέχει τη συνάρτηση
   αξιολόγησης, όπως το αντικείμενο ψευδωνύμου τύπου ή μεταβλητής
   τύπου.

   Το *format* μπορεί να χρησιμοποιηθεί για τον έλεγχο της μορφής στην
   οποία επιστρέφεται η τιμή:

      >>> type Alias = undefined
      >>> call_evaluate_function(Alias.evaluate_value, Format.VALUE)
      Traceback (most recent call last):
      ...
      NameError: name 'undefined' is not defined
      >>> call_evaluate_function(Alias.evaluate_value, Format.FORWARDREF)
      ForwardRef('undefined')
      >>> call_evaluate_function(Alias.evaluate_value, Format.STRING)
      'undefined'

   Added in version 3.14.

annotationlib.get_annotate_from_class_namespace(namespace)

   Ανακτά τη *συνάρτηση σχολιασμού* από ένα λεξικό χώρου ονομάτων
   κλάσης *namespace*. Επιστρέφει "None" αν ο χώρος ονομάτων δεν
   περιέχει συνάρτηση annotate. Eίναι κυρίως χρήσιμο πριν η κλάση
   δημιουργηθεί πλήρως (π.χ., σε μια μετάκληση)· μετά την ύπαρξη της
   κλάσης, η συνάρτηση σχολιασμού μπορεί να ανακτηθεί με την
   "cls.__annotate__". Δείτε παρακάτω για ένα παράδειγμα χρήσης αυτής
   της συνάρτησης σε μια μετάκληση.

   Added in version 3.14.

annotationlib.get_annotations(obj, *, globals=None, locals=None, eval_str=False, format=Format.VALUE)

   Υπολογίζει το λεξικό των επισημάνσεων (annotations) για ένα
   αντικείμενο.

   Το *obj* μπορεί να είναι μια καλέσιμη οντότητα, μία κλάση, ένα
   module ή άλλο αντικείμενο με χαρακτηριστικά "__annotate__" ή
   "__annotations__". Το πέρασμα οποιουδήποτε άλλου αντικειμένου κάνει
   raise την "TypeError".

   Η παράμετρος *format* ελέγχει τη μορφή στην οποία επιστρέφονται οι
   επισημάνσεις (annotations) και πρέπει να είναι μέλος του enum
   "Format" ή το ακέραιο ισοδύναμό του. Οι διάφορες μορφές λειτουργούν
   ως εξής:

   * VALUE: Δοκιμάζεται πρώτα το "object.__annotations__"· αν αυτό δεν
     υπάρχει, καλείται η συνάρτηση "object.__annotate__" αν υπάρχει.

   * FORWARDREF: Αν το "object.__annotations__" υπάρχει και μπορεί να
     αξιολογηθεί επιτυχώς, χρησιμοποιείται· διαφορετικά, καλείται η
     συνάρτηση "object.__annotate__". Αν ούτε αυτή υπάρχει,
     δοκιμάζεται ξανά το "object.__annotations__" και κάθε σφάλμα από
     την πρόσβαση σε αυτό γίνεται raise ξανά.

     * Όταν καλείται το "object.__annotate__", καλείται πρώτα με το
       "FORWARDREF". Αν αυτό δεν είναι υλοποιημένο, στη συνέχεια
       ελέγχει αν υποστηρίζεται το "VALUE_WITH_FAKE_GLOBALS" και το
       χρησιμοποιεί στο περιβάλλον με τα ψεύτικα καθολικά. Αν καμία
       από αυτές τις μορφές δεν υποστηρίζεται, θα καταφύγει στη χρήση
       του "VALUE". Αν το "VALUE" αποτύχει, το σφάλμα από αυτή την
       κλήση θα γίνει raise.

   * STRING: Αν υπάρχει το "object.__annotate__", καλείται πρώτο·
     διαφορετικά, χρησιμοποιείται το "object.__annotations__" και
     μετατρέπεται σε συμβολοσειρά χρησιμοποιώντας την
     "annotations_to_string()".

     * Όταν καλείται το "object.__annotate__", καλείται πρώτα με
       "STRING". Αν αυτό δεν είναι υλοποιημένο, στη συνέχεια ελέγχει
       αν υποστηρίζεται το "VALUE_WITH_FAKE_GLOBALS" και το
       χρησιμοποιεί στο περιβάλλον με τα ψεύτικα καθολικά. Αν καμία
       από αυτές τις μορφές δεν υποστηρίζεται, θα καταφύγει στη χρήση
       του "VALUE" με το αποτέλεσμα να μετατρέπεται χρησιμοποιώντας
       την "annotations_to_string()". Αν το "VALUE" αποτύχει, το
       σφάλμα από αυτή την κλήση θα γίνει raise.

   Επιστρέφει ένα λεξικό. Η "get_annotations()" επιστρέφει ένα νέο
   λεξικό κάθε φορά που καλείται· αν κληθεί δύο φορές στο ίδιο
   αντικείμενο θα επιστρέψει δύο διαφορετικά αλλά ισοδύναμα λεξικά.

   Αυτή η συνάρτηση χειρίζεται αρκετές λεπτομέρειες για εσάς:

   * Αν το *eval_str* είναι αληθές, οι τιμές τύπου "str" θα
     απομετατραπούν από συμβολοσειρές χρησιμοποιώντας τη "eval()".
     Προορίζεται για χρήση με επισημάνσεις (annotations) ως
     συμβολοσειρές ("from __future__ import annotations"). Είναι λάθος
     να οριστεί το *eval_str* ως αληθές με μορφές διαφορετικές από το
     "Format.VALUE".

   * Αν το *obj* δεν έχει λεξικό επισημάνσεων (annotations),
     επιστρέφει ένα κενό λεξικό. (Οι συναρτήσεις και οι μέθοδοι έχουν
     πάντα λεξικό επισημάνσεων· οι κλάσεις, τα modules και άλλοι τύποι
     καλέσιμων μπορεί να μην έχουν.)

   * Αγνοεί τις κληρονομημένες επισημάνσεις (annotations) σε κλάσεις,
     καθώς και τις επισημάνσεις (annotations) σε μετακλάσεις. Αν μια
     κλάση δεν έχει το δικό της λεξικό επισημάνσεων (annotations),
     επιστρέφει ένα κενό λεξικό.

   * Όλες οι προσβάσεις σε μέλη αντικειμένων και τιμές λεξικών
     γίνονται χρησιμοποιώντας τις "getattr()" και "dict.get()" για
     λόγους ασφαλείας.

   Το *eval_str* ελέγχει αν οι τιμές τύπου "str" αντικαθίστανται ή όχι
   με το αποτέλεσμα της κλήσης της "eval()" σε αυτές τις τιμές:

   * Αν το eval_str είναι αληθές, η "eval()" καλείται σε τιμές τύπου
     "str". (Σημειώστε ότι η "get_annotations()" δεν πιάνει
     εξαιρέσεις· αν η "eval()" κάνει raise μια εξαίρεση, θα ξετυλίξει
     τη στοίβα πέρα από την κλήση της "get_annotations()".)

   * Αν το *eval_str* είναι ψευδές (η προεπιλογή), οι τιμές τύπου
     "str" παραμένουν αμετάβλητες.

   Τα *globals* και *locals* περνιούνται στην "eval()"· δείτε την
   τεκμηρίωση της "eval()" για περισσότερες πληροφορίες. Αν το
   *globals* ή το *locals* είναι "None", αυτή η συνάρτηση μπορεί να
   αντικαταστήσει αυτή την τιμή με μια προεπιλογή ειδική για το
   πλαίσιο, εξαρτώμενη από το "type(obj)":

   * Αν το *obj* είναι module, η προεπιλογή για το *globals* είναι
     "obj.__dict__".

   * Αν το *obj* είναι κλάση, η προεπιλογή για το *globals* είναι
     "sys.modules[obj.__module__].__dict__" και η προεπιλογή για το
     *locals* είναι ο χώρος ονομάτων κλάσης του *obj*.

   * Αν το *obj* είναι καλέσιμο, η προεπιλογή για το *globals* είναι
     "obj.__globals__", παρόλο που αν το *obj* είναι μια περιτυλιγμένη
     συνάρτηση (χρησιμοποιώντας "functools.update_wrapper()") ή ένα
     αντικείμενο της "functools.partial", ξετυλίγεται μέχρι να βρεθεί
     μια μη περιτυλιγμένη συνάρτηση.

   Η κλήση της "get_annotations()" είναι η βέλτιστη πρακτική για την
   πρόσβαση στο λεξικό των επισημάνσεων (annotations) οποιουδήποτε
   αντικειμένου. Δείτε το Annotations Best Practices για περισσότερες
   πληροφορίες σχετικά με τις βέλτιστες πρακτικές των επισημάνσεων
   (annotations).

      >>> def f(a: int, b: str) -> float:
      ...     pass
      >>> get_annotations(f)
      {'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'float'>}

   Added in version 3.14.

annotationlib.type_repr(value)

   Μετατρέπει μια αυθαίρετη τιμή Python σε μια μορφή κατάλληλη για
   χρήση από τη μορφή "STRING". Αυτή καλεί την "repr()" για τα
   περισσότερα αντικείμενα, αλλά έχει ειδικό χειρισμό για ορισμένα
   αντικείμενα, όπως τα αντικείμενα τύπου.

   Αυτό προορίζεται ως βοηθητική λειτουργία για συναρτήσεις annotate
   παρεχόμενες από τον χρήστη που υποστηρίζουν τη μορφή "STRING", αλλά
   δεν έχουν πρόσβαση στον κώδικα που δημιουργεί τις επισημάνσεις
   (annotations). Μπορεί επίσης να χρησιμοποιηθεί για να παρέχει μια
   φιλική προς τον χρήστη αναπαράσταση συμβολοσειράς για άλλα
   αντικείμενα που περιέχουν τιμές που συναντώνται συνήθως σε
   επισημάνσεις (annotations).

   Added in version 3.14.


Συνταγές
========


Χρήση των επισημάνσεων (annotations) σε μετακλάση
-------------------------------------------------

Μια μετακλάση μπορεί να θέλει να επιθεωρήσει ή ακόμη και να
τροποποιήσει τις επισημάνσεις (annotations) στο σώμα μιας κλάσης κατά
τη δημιουργία της κλάσης. Αυτό απαιτεί την ανάκτηση των επισημάνσεων
(annotations) από το λεξικό χώρου ονομάτων της κλάσης. Για κλάσεις που
δημιουργούνται με το "from __future__ import annotations", οι
επισημάνσεις (annotations) θα βρίσκονται στο κλειδί "__annotations__"
του λεξικού. Για άλλες κλάσεις με επισημάνσεις (annotations), η
"get_annotate_from_class_namespace()" μπορεί να χρησιμοποιηθεί για να
πάρει τη συνάρτηση annotate, και η "call_annotate_function()" μπορεί
να χρησιμοποιηθεί για να την καλέσει και να ανακτήσει τις επισημάνσεις
(annotations). Η χρήση της μορφής "FORWARDREF" συνήθως θα είναι η
καλύτερη, επειδή επιτρέπει στις επισημάνσεις (annotations) να
αναφέρονται σε ονόματα που δεν μπορούν ακόμη να επιλυθούν όταν
δημιουργείται η κλάση.

Για να τροποποιήσετε τις επισημάνσεις (annotations), είναι καλύτερο να
δημιουργήσετε μια περιτυλιγμένη συνάρτηση annotate που καλεί την
αρχική συνάρτηση annotate, κάνει τις απαραίτητες προσαρμογές και
επιστρέφει το αποτέλεσμα.

Παρακάτω είναι ένα παράδειγμα μιας μετακλάσης, που φιλτράρει όλες τις
επισημάνσεις (annotations) "typing.ClassVar" από την κλάση και τα
τοποθετεί σε ένα ξεχωριστό χαρακτηριστικό:

   import annotationlib
   import typing

   class ClassVarSeparator(type):
      def __new__(mcls, name, bases, ns):
         if "__annotations__" in ns:  # from __future__ import annotations
            annotations = ns["__annotations__"]
            classvar_keys = {
               key for key, value in annotations.items()
               # Use string comparison for simplicity; a more robust solution
               # could use annotationlib.ForwardRef.evaluate
               if value.startswith("ClassVar")
            }
            classvars = {key: annotations[key] for key in classvar_keys}
            ns["__annotations__"] = {
               key: value for key, value in annotations.items()
               if key not in classvar_keys
            }
            wrapped_annotate = None
         elif annotate := annotationlib.get_annotate_from_class_namespace(ns):
            annotations = annotationlib.call_annotate_function(
               annotate, format=annotationlib.Format.FORWARDREF
            )
            classvar_keys = {
               key for key, value in annotations.items()
               if typing.get_origin(value) is typing.ClassVar
            }
            classvars = {key: annotations[key] for key in classvar_keys}

            def wrapped_annotate(format):
               annos = annotationlib.call_annotate_function(annotate, format, owner=typ)
               return {key: value for key, value in annos.items() if key not in classvar_keys}

         else:  # no annotations
            classvars = {}
            wrapped_annotate = None
         typ = super().__new__(mcls, name, bases, ns)

         if wrapped_annotate is not None:
            # Wrap the original __annotate__ with a wrapper that removes ClassVars
            typ.__annotate__ = wrapped_annotate
         typ.classvars = classvars  # Store the ClassVars in a separate attribute
         return typ


Creating a custom callable annotate function
--------------------------------------------

Custom *annotate functions* may be literal functions like those
automatically generated for functions, classes, and modules. Or, they
may wish to utilise the encapsulation provided by classes, in which
case any *callable* can be used as an *annotate function*.

To provide the "VALUE", "STRING", or "FORWARDREF" formats directly, an
*annotate function* must provide the following attribute:

* A callable "__call__" with signature "__call__(format, /) -> dict",
  that does not raise a "NotImplementedError" when called with a
  supported format.

To provide the "VALUE_WITH_FAKE_GLOBALS" format, which is used to
automatically generate "STRING" or "FORWARDREF" if they are not
supported directly, *annotate functions* must provide the following
attributes:

* A callable "__call__" with signature "__call__(format, /) -> dict",
  that does not raise a "NotImplementedError" when called with
  "VALUE_WITH_FAKE_GLOBALS".

* A code object "__code__" containing the compiled code for the
  annotate function.

* Optional: A tuple of the function's positional defaults
  "__kwdefaults__", if the function represented by "__code__" uses any
  positional defaults.

* Optional: A dict of the function's keyword defaults "__defaults__",
  if the function represented by "__code__" uses any keyword defaults.

* Optional: All other function attributes.

   class Annotate:
       called_formats = []

       def __call__(self, format=None, /, *, _self=None):
           # When called with fake globals, `_self` will be the
           # actual self value, and `self` will be the format.
           if _self is not None:
               self, format = _self, self

           self.called_formats.append(format)
           if format <= 2:  # VALUE or VALUE_WITH_FAKE_GLOBALS
               return {"x": MyType}
           raise NotImplementedError

       __code__ = __call__.__code__
       __defaults__ = (None,)
       __kwdefaults__ = property(lambda self: dict(_self=self))

       __globals__ = {}
       __builtins__ = {}
       __closure__ = None

This can then be called with:

   >>> from annotationlib import call_annotate_function, Format
   >>> call_annotate_function(Annotate(), format=Format.STRING)
   {'x': 'MyType'}

Or used as the annotate function for an object:

   >>> from annotationlib import get_annotations, Format
   >>> class C:
   ...   pass
   >>> C.__annotate__ = Annotate()
   >>> get_annotations(Annotate(), format=Format.STRING)
   {'x': 'MyType'}


Περιορισμοί της μορφής "STRING"
===============================

Η μορφή "STRING" προορίζεται για να προσεγγίζει τον πηγαίο κώδικα του
σχολιασμού, αλλά η στρατηγική υλοποίησης που χρησιμοποιείται σημαίνει
ότι δεν είναι πάντα δυνατή η ανάκτηση του ακριβούς πηγαίου κώδικα.

Πρώτον, ο μετατροπέας συμβολοσειράς φυσικά δεν μπορεί να ανακτήσει
πληροφορίες που δεν υπάρχουν στον μεταγλωττισμένο κώδικα,
συμπεριλαμβανομένων των σχολίων, των λευκών χαρακτήρων, των
παρενθέσεων και των πράξεων που απλοποιούνται από τον μεταγλωττιστή.

Δεύτερον, ο μετατροπέας συμβολοσειράς μπορεί να παρεμβάλει σχεδόν όλες
τις πράξεις που περιλαμβάνουν ονόματα που αναζητούνται σε κάποια
εμβέλεια, αλλά δεν μπορεί να παρεμβάλει πράξεις που λειτουργούν πλήρως
πάνω σε σταθερές. Ως επακόλουθο, αυτό σημαίνει επίσης ότι δεν είναι
ασφαλές να ζητείται η μορφή "STRING" σε μη αξιόπιστο κώδικα: η Python
είναι αρκετά ισχυρή ώστε να μπορεί να επιτευχθεί αυθαίρετη εκτέλεση
κώδικα ακόμη και χωρίς πρόσβαση σε global ή builtins. Για παράδειγμα:

   >>> def f(x: (1).__class__.__base__.__subclasses__()[-1].__init__.__builtins__["print"]("Hello world")): pass
   ...
   >>> annotationlib.get_annotations(f, format=annotationlib.Format.STRING)
   Hello world
   {'x': 'None'}

Σημείωση:

  Αυτό το συγκεκριμένο παράδειγμα λειτουργεί κατά τη στιγμή της
  συγγραφής, αλλά βασίζεται σε λεπτομέρειες υλοποίησης και δεν είναι
  εγγυημένο ότι θα λειτουργεί στο μέλλον.

Μεταξύ των διαφορετικών ειδών εκφράσεων που υπάρχουν στην Python, όπως
αναπαρίστανται από το module "ast", ορισμένες εκφράσεις
υποστηρίζονται, που σημαίνει ότι η μορφή "STRING" μπορεί γενικά να
ανακτήσει τον αρχικό πηγαίο κώδικα· άλλες δεν υποστηρίζονται, που
σημαίνει ότι μπορεί να οδηγήσουν σε λανθασμένη έξοδο ή σφάλμα.

Τα ακόλουθα υποστηρίζονται (μερικές φορές με επιφυλάξεις):

* "ast.BinOp"

* "ast.UnaryOp"

  * Οι "ast.Invert" ("~"), "ast.UAdd" ("+") και "ast.USub" ("-")
    υποστηρίζονται

  * Η "ast.Not" ("not") δεν υποστηρίζεται

* "ast.Dict" (εκτός αν χρησιμοποιείται αποσυσκευασία "**")

* "ast.Set"

* "ast.Compare"

  * Οι "ast.Eq" και "ast.NotEq" υποστηρίζονται

  * Οι "ast.Lt", "ast.LtE", "ast.Gt" και "ast.GtE" υποστηρίζονται,
    αλλά το τελεστέο μπορεί να αναστραφεί

  * Οι "ast.Is", "ast.IsNot", "ast.In" και "ast.NotIn" δεν
    υποστηρίζονται

* "ast.Call" (εκτός αν χρησιμοποιείται αποσυσκευασία "**")

* "ast.Constant" (αν και όχι η ακριβής αναπαράσταση της σταθεράς· για
  παράδειγμα, οι ακολουθίες διαφυγής σε συμβολοσειρές χάνονται· οι
  δεκαεξαδικοί αριθμοί μετατρέπονται σε δεκαδικούς)

* "ast.Attribute" (υποθέτοντας ότι η τιμή δεν είναι σταθερά)

* "ast.Subscript" (υποθέτοντας ότι η τιμή δεν είναι σταθερά)

* "ast.Starred" (αποσυσκευασία "*")

* "ast.Name"

* "ast.List"

* "ast.Tuple"

* "ast.Slice"

Τα ακόλουθα δεν υποστηρίζονται, αλλά εγείρει ένα ενημερωτικό σφάλμα
όταν συναντώνται από τον μετατροπέα συμβολοσειράς:

* "ast.FormattedValue" (f-strings· το σφάλμα δεν ανιχνεύεται αν
  χρησιμοποιούνται προδιαγραφές μετατροπής όπως "!r")

* "ast.JoinedStr" (f-strings)

Τα ακόλουθα δεν υποστηρίζονται και οδηγούν σε λανθασμένη έξοδο:

* "ast.BoolOp" ("and" και "or")

* "ast.IfExp"

* "ast.Lambda"

* "ast.ListComp"

* "ast.SetComp"

* "ast.DictComp"

* "ast.GeneratorExp"

Τα ακόλουθα δεν επιτρέπονται σε εμβέλειες των επισημάνσεων
(annotations) και επομένως δεν είναι σχετικά:

* "ast.NamedExpr" (":=")

* "ast.Await"

* "ast.Yield"

* "ast.YieldFrom"


Περιορισμοί της μορφής "FORWARDREF"
===================================

Η μορφή "FORWARDREF" στοχεύει στην παραγωγή πραγματικών τιμών όσο το
δυνατόν περισσότερο, αντικαθιστώντας οτιδήποτε δεν μπορεί να επιλυθεί
με αντικείμενα της "ForwardRef". Επηρεάζεται γενικά από τους ίδιους
περιορισμούς με τη μορφή "STRING": οι επισημάνσεις (annotations) που
εκτελούν πράξεις σε λεκτικές σταθερές ή που χρησιμοποιούν μη
υποστηριζόμενους τύπους εκφράσεων μπορεί να κάνουν raise εξαιρέσεις
όταν αξιολογούνται χρησιμοποιώντας τη μορφή "FORWARDREF".

Παρακάτω είναι μερικά παραδείγματα της συμπεριφοράς με μη
υποστηριζόμενες εκφράσεις:

   >>> from annotationlib import get_annotations, Format
   >>> def zerodiv(x: 1 / 0): ...
   >>> get_annotations(zerodiv, format=Format.STRING)
   Traceback (most recent call last):
     ...
   ZeroDivisionError: division by zero
   >>> get_annotations(zerodiv, format=Format.FORWARDREF)
   Traceback (most recent call last):
     ...
   ZeroDivisionError: division by zero
   >>> def ifexp(x: 1 if y else 0): ...
   >>> get_annotations(ifexp, format=Format.STRING)
   {'x': '1'}


Επιπτώσεις ασφαλείας από την ενδοσκόπηση των επισημάνσεων (annotations)
=======================================================================

Η περισσότερη λειτουργικότητα σε αυτό το module περιλαμβάνει την
εκτέλεση κώδικα που σχετίζεται με επισημάνσεις (annotations), ο οποίος
μπορεί στη συνέχεια να κάνει αυθαίρετα πράγματα. Για παράδειγμα, η
"get_annotations()" μπορεί να καλέσει μια αυθαίρετη *συνάρτηση
annotate*, και η "ForwardRef.evaluate()" μπορεί να καλέσει την
"eval()" σε μια αυθαίρετη συμβολοσειρά. Ο κώδικας που περιέχεται σε
μια επισήμανση (annotation) μπορεί να κάνει αυθαίρετες κλήσεις
συστήματος, να μπει σε ατέρμονο βρόχο ή να εκτελέσει οποιαδήποτε άλλη
λειτουργία. Αυτό ισχύει επίσης για κάθε πρόσβαση στο χαρακτηριστικό
"__annotations__", και για διάφορες συναρτήσεις στο module "typing"
που εργάζονται με επισημάνσεις (annotations), όπως η
"typing.get_type_hints()".

Κάθε ζήτημα ασφαλείας, που προκύπτει από αυτό, ισχύει επίσης αμέσως
μετά την εισαγωγή κώδικα που μπορεί να περιέχει μη αξιόπιστες
επισημάνσεις (annotations): η εισαγωγή κώδικα μπορεί πάντα να
προκαλέσει την εκτέλεση αυθαίρετων λειτουργιών. Ωστόσο, είναι μη
ασφαλές να γίνονται αποδεκτές συμβολοσειρές ή άλλη είσοδος από μη
αξιόπιστη πηγή και να περνιούνται σε οποιοδήποτε από τα API για
ενδοσκόπηση των επισημάνσεων (annotations), για παράδειγμα με την
επεξεργασία ενός λεξικού "__annotations__" ή την άμεση δημιουργία ενός
αντικειμένου της "ForwardRef".
