Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 508 – Spezifikation für Abhängigkeiten von Python-Softwarepaketen

Autor:
Robert Collins <rbtcollins at hp.com>
BDFL-Delegate:
Donald Stufft <donald at stufft.io>
Discussions-To:
Distutils-SIG Liste
Status:
Final
Typ:
Standards Track
Thema:
Packaging
Erstellt:
11. Nov. 2015
Post-History:
05. Nov. 2015, 16. Nov. 2015
Resolution:
Distutils-SIG Nachricht

Inhaltsverzeichnis

Wichtig

Diese PEP ist ein historisches Dokument. Die aktuelle, kanonische Spezifikation, Abhängigkeitsspezifizierer, wird auf der PyPA Spezifikationsseite gepflegt.

×

Siehe den PyPA-Spezifikations-Update-Prozess, um Änderungen vorzuschlagen.

Zusammenfassung

Diese PEP spezifiziert die Sprache, die zur Beschreibung von Abhängigkeiten für Pakete verwendet wird. Sie zieht eine Grenze bei der Beschreibung einer einzelnen Abhängigkeit – die verschiedenen Arten von Abhängigkeiten und wann sie installiert werden sollten, sind ein übergeordnetes Problem. Die Absicht ist, einen Baustein für übergeordnete Spezifikationen bereitzustellen.

Die Aufgabe einer Abhängigkeit besteht darin, Tools wie pip [1] in die Lage zu versetzen, das richtige Paket zum Installieren zu finden. Manchmal ist dies sehr locker – es wird nur ein Name angegeben, manchmal sehr spezifisch – und verweist auf eine bestimmte Datei, die installiert werden soll. Manchmal sind Abhängigkeiten nur auf einer Plattform relevant, oder es sind nur bestimmte Versionen akzeptabel, so dass die Sprache erlaubt, all diese Fälle zu beschreiben.

Die definierte Sprache ist ein kompaktes zeilenbasiertes Format, das bereits weit verbreitet in den Pip-Requirements-Dateien verwendet wird, obwohl wir die Behandlung von Befehlszeilenoptionen, die diese Dateien zulassen, nicht spezifizieren. Es gibt einen Vorbehalt – die URL-Referenzform, die in PEP 440 spezifiziert ist, ist in Pip tatsächlich nicht implementiert, aber da PEP 440 akzeptiert wurde, verwenden wir dieses Format anstelle des aktuellen nativen Pip-Formats.

Motivation

Jede Spezifikation im Python-Packaging-Ökosystem, die Listen von Abhängigkeiten verbrauchen muss, muss auf einer genehmigten PEP dafür aufbauen, aber PEP 426 ist größtenteils aspirativ – und es gibt bereits bestehende Implementierungen der Abhängigkeitsspezifikation, die wir stattdessen übernehmen können. Die bestehenden Implementierungen sind praxiserprobt und benutzerfreundlich, daher ist ihre Übernahme argumentativ viel besser, als ein aspiratives, nicht konsumiertes Format zu genehmigen.

Spezifikation

Beispiele

Alle Funktionen der Sprache, die mit einer namensbasierten Suche angezeigt werden

requests [security,tests] >= 2.8.1, == 2.8.* ; python_version < "2.7"

Eine minimale URL-basierte Suche

pip @ https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686

Konzepte

Eine Abhängigkeitsspezifikation gibt immer einen Distributionsnamen an. Sie kann Extras enthalten, die die Abhängigkeiten der benannten Distribution erweitern, um optionale Funktionen zu ermöglichen. Die installierte Version kann über Versionsbeschränkungen gesteuert oder durch Angabe der URL zu einem bestimmten zu installierenden Artefakt gesteuert werden. Schließlich kann die Abhängigkeit mithilfe von Umgebungskennzeichnungen bedingt gemacht werden.

Grammatik

Wir behandeln zunächst kurz die Grammatik und gehen dann später auf die Semantik jedes Abschnitts ein.

Eine Distributionsspezifikation wird in ASCII-Text geschrieben. Wir verwenden eine Parsley [2] Grammatik, um eine präzise Grammatik bereitzustellen. Es wird erwartet, dass die Spezifikation in ein größeres System eingebettet wird, das Rahmenbedingungen wie Kommentare, Mehrzeilenunterstützung über Fortsetzungen oder andere ähnliche Funktionen bietet.

Die vollständige Grammatik einschließlich Annotationen zum Aufbau eines nützlichen Parse-Baums ist am Ende der PEP enthalten.

Versionen können gemäß den Regeln von PEP 440 angegeben werden. (Hinweis: URI ist in std-66 definiert)

version_cmp   = wsp* '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '==='
version       = wsp* ( letterOrDigit | '-' | '_' | '.' | '*' | '+' | '!' )+
version_one   = version_cmp version wsp*
version_many  = version_one (wsp* ',' version_one)*
versionspec   = ( '(' version_many ')' ) | version_many
urlspec       = '@' wsp* <URI_reference>

Umgebungskennzeichnungen ermöglichen es, eine Spezifikation nur unter bestimmten Umständen wirksam werden zu lassen.

marker_op     = version_cmp | (wsp* 'in') | (wsp* 'not' wsp+ 'in')
python_str_c  = (wsp | letter | digit | '(' | ')' | '.' | '{' | '}' |
                 '-' | '_' | '*' | '#' | ':' | ';' | ',' | '/' | '?' |
                 '[' | ']' | '!' | '~' | '`' | '@' | '$' | '%' | '^' |
                 '&' | '=' | '+' | '|' | '<' | '>' )
dquote        = '"'
squote        = '\\''
python_str    = (squote (python_str_c | dquote)* squote |
                 dquote (python_str_c | squote)* dquote)
env_var       = ('python_version' | 'python_full_version' |
                 'os_name' | 'sys_platform' | 'platform_release' |
                 'platform_system' | 'platform_version' |
                 'platform_machine' | 'platform_python_implementation' |
                 'implementation_name' | 'implementation_version' |
                 'extra' # ONLY when defined by a containing layer
                 )
marker_var    = wsp* (env_var | python_str)
marker_expr   = marker_var marker_op marker_var
              | wsp* '(' marker wsp* ')'
marker_and    = marker_expr wsp* 'and' marker_expr
              | marker_expr
marker_or     = marker_and wsp* 'or' marker_and
                  | marker_and
marker        = marker_or
quoted_marker = ';' wsp* marker

Optionale Komponenten einer Distribution können über das Extras-Feld spezifiziert werden.

identifier_end = letterOrDigit | (('-' | '_' | '.' )* letterOrDigit)
identifier    = letterOrDigit identifier_end*
name          = identifier
extras_list   = identifier (wsp* ',' wsp* identifier)*
extras        = '[' wsp* extras_list? wsp* ']'

Was uns zu einer Regel für namensbasierte Anforderungen führt.

name_req      = name wsp* extras? wsp* versionspec? wsp* quoted_marker?

Und einer Regel für direkte Referenzspezifikationen.

url_req       = name wsp* extras? wsp* urlspec wsp+ quoted_marker?

Was zu der einheitlichen Regel führt, die eine Abhängigkeit spezifizieren kann.

specification = wsp* ( url_req | name_req ) wsp*

Leerzeichen

Nicht zeilenbrechende Leerzeichen sind größtenteils optional und ohne semantische Bedeutung. Die einzige Ausnahme ist die Erkennung des Endes einer URL-Anforderung.

Namen

Python-Distributionsnamen sind derzeit in PEP 345 definiert. Namen fungieren als primäre Kennung für Distributionen. Sie sind in allen Abhängigkeitsspezifikationen vorhanden und reichen aus, um allein eine Spezifikation zu sein. PyPI stellt jedoch strenge Einschränkungen für Namen auf – sie müssen einem fallunempfindlichen Regex entsprechen, sonst werden sie nicht akzeptiert. Dementsprechend beschränken wir in dieser PEP die zulässigen Werte für Bezeichner auf diesen Regex. Eine vollständige Neudefinition des Namens kann in einer zukünftigen Metadaten-PEP erfolgen. Der Regex (ausgeführt mit re.IGNORECASE) lautet:

^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$

Extras

Ein Extra ist ein optionaler Teil einer Distribution. Distributionen können beliebig viele Extras angeben, und jedes Extra führt zur Deklaration zusätzlicher Abhängigkeiten der Distribution, **wenn** das Extra in einer Abhängigkeitsspezifikation verwendet wird. Zum Beispiel:

requests[security]

Extras vereinigen die von ihnen definierten Abhängigkeiten mit den Abhängigkeiten der Distribution, an die sie angehängt sind. Das obige Beispiel würde dazu führen, dass requests, requests' eigene Abhängigkeiten und auch alle Abhängigkeiten, die im „security“-Extra von requests aufgeführt sind, installiert werden.

Wenn mehrere Extras aufgeführt sind, werden alle Abhängigkeiten vereinigt.

Versionen

Weitere Details zu Versionsnummern und Versionsvergleichen finden Sie in PEP 440. Versionsspezifikationen begrenzen die zu verwendenden Versionen einer Distribution. Sie gelten nur für Distributionen, die per Namen gesucht werden, nicht über eine URL. Versionsvergleiche werden auch in der Kennzeichnungsfunktion verwendet. Die optionalen Klammern um eine Version sind aus Kompatibilitätsgründen mit PEP 345 vorhanden, sollten aber nicht generiert, sondern nur akzeptiert werden.

Umgebungsmarker

Umgebungskennzeichnungen ermöglichen es einer Abhängigkeitsspezifikation, eine Regel anzugeben, die beschreibt, wann die Abhängigkeit verwendet werden soll. Betrachten Sie zum Beispiel ein Paket, das argparse benötigt. In Python 2.7 ist argparse immer vorhanden. Auf älteren Python-Versionen muss es als Abhängigkeit installiert werden. Dies kann wie folgt ausgedrückt werden:

argparse;python_version<"2.7"

Ein Marker-Ausdruck ergibt entweder True oder False. Wenn er False ergibt, sollte die Abhängigkeitsspezifikation ignoriert werden.

Die Marker-Sprache ist von Python selbst inspiriert und wurde wegen der Möglichkeit, sie sicher auszuwerten, ohne beliebigen Code auszuführen, der zu einer Sicherheitslücke werden könnte, gewählt. Marker wurden erstmals in PEP 345 standardisiert. Diese PEP behebt einige Probleme, die im Design von PEP 426 beobachtet wurden.

Vergleiche in Marker-Ausdrücken werden durch den Vergleichsoperator typisiert. Die <marker_op>-Operatoren, die nicht in <version_cmp> enthalten sind, verhalten sich genauso wie Strings in Python. Die <version_cmp>-Operatoren verwenden die PEP 440-Versionsvergleichsregeln, wenn diese definiert sind (d. h. wenn beide Seiten einen gültigen Versionsspezifizierer haben). Wenn kein definiertes PEP 440-Verhalten vorhanden ist und der Operator in Python existiert, greift der Operator auf das Python-Verhalten zurück. Andernfalls sollte ein Fehler ausgelöst werden. z.B. die folgenden ergeben Fehler

"dog" ~= "fred"
python_version ~= "surprise"

Vom Benutzer bereitgestellte Konstanten werden immer als Zeichenketten mit einfachen Anführungszeichen (') oder doppelten Anführungszeichen (") kodiert. Beachten Sie, dass Backslash-Escapes nicht definiert sind, aber bestehende Implementierungen sie unterstützen. Sie sind nicht in dieser Spezifikation enthalten, da sie Komplexität hinzufügen und es heute keinen erkennbaren Bedarf dafür gibt. Ebenso definieren wir keine Unterstützung für Nicht-ASCII-Zeichen: Alle Laufzeitvariablen, auf die wir uns beziehen, werden voraussichtlich nur ASCII-basiert sein.

Die Variablen in der Marker-Grammatik wie „os_name“ lösen Werte auf, die zur Laufzeit in Python nachgeschlagen werden. Mit Ausnahme von „extra“ sind alle Werte auf allen Python-Versionen heute definiert – es ist ein Fehler in der Implementierung von Markern, wenn ein Wert nicht definiert ist.

Unbekannte Variablen müssen einen Fehler auslösen, anstatt zu einem Vergleich zu führen, der True oder False ergibt.

Variablen, deren Wert auf einer bestimmten Python-Implementierung nicht berechnet werden kann, sollten für Versionen als 0 und für alle anderen Variablen als leere Zeichenkette ausgewertet werden.

Die Variable „extra“ ist speziell. Sie wird von Wheels verwendet, um anzuzeigen, welche Spezifikationen für ein bestimmtes Extra in der METADATA-Datei eines Wheels gelten, aber da die METADATA-Datei auf einer Entwurfsversion von PEP 426 basiert, gibt es dafür derzeit keine Spezifikation. Unabhängig davon sollte die Variable „extra“ außerhalb eines Kontexts, in dem diese spezielle Behandlung stattfindet, wie alle anderen unbekannten Variablen zu einem Fehler führen.

Marker Python-Äquivalent Beispielwerte
os_name os.name posix, java
sys_platform sys.platform linux, linux2, darwin, java1.8.0_51 (beachten Sie, dass „linux“ von Python3 und „linux2“ von Python2 stammt)
platform_machine platform.machine() x86_64
platform_python_implementation platform.python_implementation() CPython, Jython
platform_release platform.release() 3.14.1-x86_64-linode39, 14.5.0, 1.8.0_51
platform_system platform.system() Linux, Windows, Java
platform_version platform.version() #1 SMP Fri Apr 25 13:07:35 EDT 2014 Java HotSpot(TM) 64-Bit Server VM, 25.51-b03, Oracle Corporation Darwin Kernel Version 14.5.0: Wed Jul 29 02:18:53 PDT 2015; root:xnu-2782.40.9~2/RELEASE_X86_64
python_version '.'.join(platform.python_version_tuple()[:2]) 3.4, 2.7
python_full_version platform.python_version() 3.4.0, 3.5.0b1
implementation_name sys.implementation.name cpython
implementation_version siehe Definition unten 3.4.0, 3.5.0b1
extra Ein Fehler, außer wenn er durch den Kontext definiert ist, der die Spezifikation interpretiert. test

Die Marker-Variable implementation_version wird von sys.implementation.version abgeleitet.

def format_full_version(info):
    version = '{0.major}.{0.minor}.{0.micro}'.format(info)
    kind = info.releaselevel
    if kind != 'final':
        version += kind[0] + str(info.serial)
    return version

if hasattr(sys, 'implementation'):
    implementation_version = format_full_version(sys.implementation.version)
else:
    implementation_version = "0"

Abwärtskompatibilität

Der Großteil dieser PEP ist bereits weit verbreitet und bietet daher keine Kompatibilitätsprobleme.

Es gibt jedoch einige Punkte, an denen sich die PEP von der eingesetzten Basis unterscheidet.

Erstens sind die direkten Referenzen von PEP 440 in der Praxis noch nicht eingesetzt worden, aber sie wurden so konzipiert, dass sie kompatibel hinzugefügt werden können, und es gibt keine bekannten Hindernisse für ihre Hinzufügung zu pip oder anderen Tools, die die vorhandenen Abhängigkeitsmetadaten in Distributionen verbrauchen – insbesondere da sie in von PyPI hochgeladenen Distributionen ohnehin nicht zulässig sein werden.

Zweitens verhalten sich die PEP 426-Marker, die einige angemessene Verbreitung erfahren haben, insbesondere in Wheels und Pip, bei Versionsvergleichen mit python_full_version „2.7.10“ anders. Insbesondere ist in 426 „2.7.10“ kleiner als „2.7.9“. Diese Rückwärtsinkompatibilität ist beabsichtigt. Wir definieren auch neue Operatoren – „~=“ und „===“ – und neue Variablen – platform_release, platform_system, implementation_name und implementation_version –, die in älteren Marker-Implementierungen nicht vorhanden sind. Die Variablen werden bei diesen Implementierungen zu Fehlern führen. Benutzer beider Funktionen müssen eine Entscheidung treffen, wann die Unterstützung im Ökosystem ausreichend verbreitet ist, dass die Verwendung keine Kompatibilitätsprobleme verursacht.

Drittens erforderte PEP 345 Klammern um Versionsspezifizierer. Um die Abhängigkeitsspezifikationen von PEP 345 zu akzeptieren, werden Klammern akzeptiert, aber sie sollten nicht generiert werden.

Begründung

Um mit neuen PEPs, die auf Umgebungskennzeichnungen angewiesen sind, fortzufahren, benötigten wir eine Spezifikation, die diese in ihrer modernen Form enthielt. Diese PEP fasst alle derzeit nicht spezifizierten Komponenten in einer spezifizierten Form zusammen.

Der Anforderungsspezifizierer wurde aus der EBNF in der Dokumentation von setuptools pkg_resources übernommen, da wir es vermeiden wollen, uns auf einen De-facto-Standard statt auf einen PEP-spezifizierten Standard zu verlassen.

Vollständige Grammatik

Die vollständige Parsley-Grammatik

wsp           = ' ' | '\t'
version_cmp   = wsp* <'<=' | '<' | '!=' | '==' | '>=' | '>' | '~=' | '==='>
version       = wsp* <( letterOrDigit | '-' | '_' | '.' | '*' | '+' | '!' )+>
version_one   = version_cmp:op version:v wsp* -> (op, v)
version_many  = version_one:v1 (wsp* ',' version_one)*:v2 -> [v1] + v2
versionspec   = ('(' version_many:v ')' ->v) | version_many
urlspec       = '@' wsp* <URI_reference>
marker_op     = version_cmp | (wsp* 'in') | (wsp* 'not' wsp+ 'in')
python_str_c  = (wsp | letter | digit | '(' | ')' | '.' | '{' | '}' |
                 '-' | '_' | '*' | '#' | ':' | ';' | ',' | '/' | '?' |
                 '[' | ']' | '!' | '~' | '`' | '@' | '$' | '%' | '^' |
                 '&' | '=' | '+' | '|' | '<' | '>' )
dquote        = '"'
squote        = '\\''
python_str    = (squote <(python_str_c | dquote)*>:s squote |
                 dquote <(python_str_c | squote)*>:s dquote) -> s
env_var       = ('python_version' | 'python_full_version' |
                 'os_name' | 'sys_platform' | 'platform_release' |
                 'platform_system' | 'platform_version' |
                 'platform_machine' | 'platform_python_implementation' |
                 'implementation_name' | 'implementation_version' |
                 'extra' # ONLY when defined by a containing layer
                 ):varname -> lookup(varname)
marker_var    = wsp* (env_var | python_str)
marker_expr   = marker_var:l marker_op:o marker_var:r -> (o, l, r)
              | wsp* '(' marker:m wsp* ')' -> m
marker_and    = marker_expr:l wsp* 'and' marker_expr:r -> ('and', l, r)
              | marker_expr:m -> m
marker_or     = marker_and:l wsp* 'or' marker_and:r -> ('or', l, r)
                  | marker_and:m -> m
marker        = marker_or
quoted_marker = ';' wsp* marker
identifier_end = letterOrDigit | (('-' | '_' | '.' )* letterOrDigit)
identifier    = < letterOrDigit identifier_end* >
name          = identifier
extras_list   = identifier:i (wsp* ',' wsp* identifier)*:ids -> [i] + ids
extras        = '[' wsp* extras_list?:e wsp* ']' -> e
name_req      = (name:n wsp* extras?:e wsp* versionspec?:v wsp* quoted_marker?:m
                 -> (n, e or [], v or [], m))
url_req       = (name:n wsp* extras?:e wsp* urlspec:v (wsp+ | end) quoted_marker?:m
                 -> (n, e or [], v, m))
specification = wsp* ( url_req | name_req ):s wsp* -> s
# The result is a tuple - name, list-of-extras,
# list-of-version-constraints-or-a-url, marker-ast or None


URI_reference = <URI | relative_ref>
URI           = scheme ':' hier_part ('?' query )? ( '#' fragment)?
hier_part     = ('//' authority path_abempty) | path_absolute | path_rootless | path_empty
absolute_URI  = scheme ':' hier_part ( '?' query )?
relative_ref  = relative_part ( '?' query )? ( '#' fragment )?
relative_part = '//' authority path_abempty | path_absolute | path_noscheme | path_empty
scheme        = letter ( letter | digit | '+' | '-' | '.')*
authority     = ( userinfo '@' )? host ( ':' port )?
userinfo      = ( unreserved | pct_encoded | sub_delims | ':')*
host          = IP_literal | IPv4address | reg_name
port          = digit*
IP_literal    = '[' ( IPv6address | IPvFuture) ']'
IPvFuture     = 'v' hexdig+ '.' ( unreserved | sub_delims | ':')+
IPv6address   = (
                  ( h16 ':'){6} ls32
                  | '::' ( h16 ':'){5} ls32
                  | ( h16 )?  '::' ( h16 ':'){4} ls32
                  | ( ( h16 ':')? h16 )? '::' ( h16 ':'){3} ls32
                  | ( ( h16 ':'){0,2} h16 )? '::' ( h16 ':'){2} ls32
                  | ( ( h16 ':'){0,3} h16 )? '::' h16 ':' ls32
                  | ( ( h16 ':'){0,4} h16 )? '::' ls32
                  | ( ( h16 ':'){0,5} h16 )? '::' h16
                  | ( ( h16 ':'){0,6} h16 )? '::' )
h16           = hexdig{1,4}
ls32          = ( h16 ':' h16) | IPv4address
IPv4address   = dec_octet '.' dec_octet '.' dec_octet '.' dec_octet
nz            = ~'0' digit
dec_octet     = (
                  digit # 0-9
                  | nz digit # 10-99
                  | '1' digit{2} # 100-199
                  | '2' ('0' | '1' | '2' | '3' | '4') digit # 200-249
                  | '25' ('0' | '1' | '2' | '3' | '4' | '5') )# %250-255
reg_name = ( unreserved | pct_encoded | sub_delims)*
path = (
        path_abempty # begins with '/' or is empty
        | path_absolute # begins with '/' but not '//'
        | path_noscheme # begins with a non-colon segment
        | path_rootless # begins with a segment
        | path_empty ) # zero characters
path_abempty  = ( '/' segment)*
path_absolute = '/' ( segment_nz ( '/' segment)* )?
path_noscheme = segment_nz_nc ( '/' segment)*
path_rootless = segment_nz ( '/' segment)*
path_empty    = pchar{0}
segment       = pchar*
segment_nz    = pchar+
segment_nz_nc = ( unreserved | pct_encoded | sub_delims | '@')+
                # non-zero-length segment without any colon ':'
pchar         = unreserved | pct_encoded | sub_delims | ':' | '@'
query         = ( pchar | '/' | '?')*
fragment      = ( pchar | '/' | '?')*
pct_encoded   = '%' hexdig
unreserved    = letter | digit | '-' | '.' | '_' | '~'
reserved      = gen_delims | sub_delims
gen_delims    = ':' | '/' | '?' | '#' | '(' | ')?' | '@'
sub_delims    = '!' | '$' | '&' | '\\'' | '(' | ')' | '*' | '+' | ',' | ';' | '='
hexdig        = digit | 'a' | 'A' | 'b' | 'B' | 'c' | 'C' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F'

Ein Testprogramm – wenn die Grammatik in einer Zeichenkette grammar ist

import os
import sys
import platform

from parsley import makeGrammar

grammar = """
    wsp ...
    """
tests = [
    "A",
    "A.B-C_D",
    "aa",
    "name",
    "name<=1",
    "name>=3",
    "name>=3,<2",
    "name@http://foo.com",
    "name [fred,bar] @ http://foo.com ; python_version=='2.7'",
    "name[quux, strange];python_version<'2.7' and platform_version=='2'",
    "name; os_name=='a' or os_name=='b'",
    # Should parse as (a and b) or c
    "name; os_name=='a' and os_name=='b' or os_name=='c'",
    # Overriding precedence -> a and (b or c)
    "name; os_name=='a' and (os_name=='b' or os_name=='c')",
    # should parse as a or (b and c)
    "name; os_name=='a' or os_name=='b' and os_name=='c'",
    # Overriding precedence -> (a or b) and c
    "name; (os_name=='a' or os_name=='b') and os_name=='c'",
    ]

def format_full_version(info):
    version = '{0.major}.{0.minor}.{0.micro}'.format(info)
    kind = info.releaselevel
    if kind != 'final':
        version += kind[0] + str(info.serial)
    return version

if hasattr(sys, 'implementation'):
    implementation_version = format_full_version(sys.implementation.version)
    implementation_name = sys.implementation.name
else:
    implementation_version = '0'
    implementation_name = ''
bindings = {
    'implementation_name': implementation_name,
    'implementation_version': implementation_version,
    'os_name': os.name,
    'platform_machine': platform.machine(),
    'platform_python_implementation': platform.python_implementation(),
    'platform_release': platform.release(),
    'platform_system': platform.system(),
    'platform_version': platform.version(),
    'python_full_version': platform.python_version(),
    'python_version': '.'.join(platform.python_version_tuple()[:2]),
    'sys_platform': sys.platform,
}

compiled = makeGrammar(grammar, {'lookup': bindings.__getitem__})
for test in tests:
    parsed = compiled(test).specification()
    print("%s -> %s" % (test, parsed))

Zusammenfassung der Änderungen an PEP 508

Die folgenden Änderungen wurden an dieser PEP basierend auf Feedback nach ihrer anfänglichen Implementierung vorgenommen.

  • Die Definition von python_version wurde von platform.python_version()[:3] zu '.'.join(platform.python_version_tuple()[:2]) geändert, um potenzielle zukünftige Versionen von Python mit 2-stelligen Haupt- und Nebenversionen (z. B. 3.10) zu berücksichtigen. [3]

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-0508.rst

Zuletzt geändert: 2025-02-20 11:58:35 GMT