mirror of
https://github.com/3minbe/DBC_Converter.git
synced 2026-05-17 09:33:59 +09:00
pip 버전 업데이트 및 인코딩 방법 수정정
This commit is contained in:
parent
02df1b0ba7
commit
e27abe2a32
@ -555,7 +555,7 @@ class MainView(QtWidgets.QMainWindow):
|
||||
|
||||
self.updateAlertText(f"변환 성공", [file_path])
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.updateAlertText(f"변환 실패: {e}", [file_path])
|
||||
self.updateAlertText(f"변환 실패\n {e}", [file_path])
|
||||
self.progress_bar.setValue(int((index + 1) / total_files * 100))
|
||||
self.status_bar.showMessage("변환 완료")
|
||||
self.progress_bar.setVisible(False)
|
||||
|
||||
@ -1,67 +1,75 @@
|
||||
import re, sys
|
||||
import re
|
||||
import sys
|
||||
|
||||
def load_dbc_file(file_path):
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
content = file.read()
|
||||
# print(f"[INFO] Successfully loaded DBC file: {file_path}")
|
||||
encodings = ['utf-8', 'cp949', 'latin1'] # 시도할 인코딩 목록
|
||||
|
||||
# 메시지와 시그널을 추출하는 정규 표현식
|
||||
message_pattern = re.compile(r'BO_\s+(\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)')
|
||||
signal_pattern = re.compile(r'SG_\s+(\w+)\s*:\s*(\d+)\|(\d+)@(\d+)([+-])\s*\(([^,]+),\s*([^)]+)\)\s*\[[^\]]+\]\s*\"[^\"]*\"\s+(\w+)')
|
||||
for encoding in encodings:
|
||||
try:
|
||||
with open(file_path, 'r', encoding=encoding) as file:
|
||||
content = file.read()
|
||||
print(f"[INFO] Successfully loaded DBC file with encoding: {encoding}")
|
||||
break # 파일을 성공적으로 읽으면 루프를 종료
|
||||
except (UnicodeDecodeError, FileNotFoundError) as e:
|
||||
print(f"[WARNING] Failed to read file with encoding {encoding}: {e}")
|
||||
content = None
|
||||
|
||||
# 메시지와 시그널 매칭
|
||||
messages = {}
|
||||
current_message = None
|
||||
|
||||
for line in content.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
current_message = None
|
||||
continue
|
||||
|
||||
message_match = message_pattern.match(line)
|
||||
if message_match:
|
||||
decimal_id = int(message_match.group(1))
|
||||
hex_id = f"0x{decimal_id:03X}"
|
||||
message_name = message_match.group(2)
|
||||
dlc = int(message_match.group(3))
|
||||
tx_ecu_name = message_match.group(4)
|
||||
current_message = message_name
|
||||
messages[current_message] = {
|
||||
"ID": hex_id,
|
||||
"DLC": dlc,
|
||||
"TX ECU name": tx_ecu_name,
|
||||
"Signals": []
|
||||
}
|
||||
elif current_message:
|
||||
signal_match = signal_pattern.match(line)
|
||||
if signal_match:
|
||||
signal_name = signal_match.group(1)
|
||||
msb = int(signal_match.group(2))
|
||||
length = int(signal_match.group(3))
|
||||
byte_order = int(signal_match.group(4))
|
||||
sign = signal_match.group(5)
|
||||
factor = float(signal_match.group(6))
|
||||
offset = float(signal_match.group(7))
|
||||
rx_ecu_name = signal_match.group(8)
|
||||
messages[current_message]["Signals"].append({
|
||||
"Signal name": signal_name,
|
||||
"msb": msb,
|
||||
"Length": length,
|
||||
"Byte order": byte_order,
|
||||
"Sign": sign,
|
||||
"Factor": factor,
|
||||
"Offset": offset,
|
||||
"RX ECU name": rx_ecu_name
|
||||
})
|
||||
|
||||
return messages
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to parse DBC file: {e}")
|
||||
if content is None:
|
||||
print(f"[ERROR] Failed to load DBC file with all attempted encodings.")
|
||||
return None
|
||||
|
||||
# 메시지와 시그널을 추출하는 정규 표현식
|
||||
message_pattern = re.compile(r'BO_\s+(\d+)\s+(\w+)\s*:\s*(\d+)\s+(\w+)')
|
||||
signal_pattern = re.compile(r'SG_\s+(\w+)\s*:\s*(\d+)\|(\d+)@(\d+)([+-])\s*\(([^,]+),\s*([^)]+)\)\s*\[[^\]]+\]\s*\"[^\"]*\"\s+(\w+)')
|
||||
|
||||
# 메시지와 시그널 매칭
|
||||
messages = {}
|
||||
current_message = None
|
||||
|
||||
for line in content.splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
current_message = None
|
||||
continue
|
||||
|
||||
message_match = message_pattern.match(line)
|
||||
if message_match:
|
||||
decimal_id = int(message_match.group(1))
|
||||
hex_id = f"0x{decimal_id:03X}"
|
||||
message_name = message_match.group(2)
|
||||
dlc = int(message_match.group(3))
|
||||
tx_ecu_name = message_match.group(4)
|
||||
current_message = message_name
|
||||
messages[current_message] = {
|
||||
"ID": hex_id,
|
||||
"DLC": dlc,
|
||||
"TX ECU name": tx_ecu_name,
|
||||
"Signals": []
|
||||
}
|
||||
elif current_message:
|
||||
signal_match = signal_pattern.match(line)
|
||||
if signal_match:
|
||||
signal_name = signal_match.group(1)
|
||||
msb = int(signal_match.group(2))
|
||||
length = int(signal_match.group(3))
|
||||
byte_order = int(signal_match.group(4))
|
||||
sign = signal_match.group(5)
|
||||
factor = float(signal_match.group(6))
|
||||
offset = float(signal_match.group(7))
|
||||
rx_ecu_name = signal_match.group(8)
|
||||
messages[current_message]["Signals"].append({
|
||||
"Signal name": signal_name,
|
||||
"msb": msb,
|
||||
"Length": length,
|
||||
"Byte order": byte_order,
|
||||
"Sign": sign,
|
||||
"Factor": factor,
|
||||
"Offset": offset,
|
||||
"RX ECU name": rx_ecu_name
|
||||
})
|
||||
|
||||
return messages
|
||||
|
||||
if __name__ == "__main__":
|
||||
file_path = sys.argv[1]
|
||||
messages = load_dbc_file(file_path)
|
||||
|
||||
BIN
__pycache__/DBC_Converter.cpython-313.pyc
Normal file
BIN
__pycache__/DBC_Converter.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -1,799 +0,0 @@
|
||||
@Switch01
|
||||
A_Rog
|
||||
Aakanksha Agrawal
|
||||
Abhinav Sagar
|
||||
ABHYUDAY PRATAP SINGH
|
||||
abs51295
|
||||
AceGentile
|
||||
Adam Chainz
|
||||
Adam Tse
|
||||
Adam Wentz
|
||||
admin
|
||||
Adolfo Ochagavía
|
||||
Adrien Morison
|
||||
Agus
|
||||
ahayrapetyan
|
||||
Ahilya
|
||||
AinsworthK
|
||||
Akash Srivastava
|
||||
Alan Yee
|
||||
Albert Tugushev
|
||||
Albert-Guan
|
||||
albertg
|
||||
Alberto Sottile
|
||||
Aleks Bunin
|
||||
Ales Erjavec
|
||||
Alethea Flowers
|
||||
Alex Gaynor
|
||||
Alex Grönholm
|
||||
Alex Hedges
|
||||
Alex Loosley
|
||||
Alex Morega
|
||||
Alex Stachowiak
|
||||
Alexander Shtyrov
|
||||
Alexandre Conrad
|
||||
Alexey Popravka
|
||||
Aleš Erjavec
|
||||
Alli
|
||||
Ami Fischman
|
||||
Ananya Maiti
|
||||
Anatoly Techtonik
|
||||
Anders Kaseorg
|
||||
Andre Aguiar
|
||||
Andreas Lutro
|
||||
Andrei Geacar
|
||||
Andrew Gaul
|
||||
Andrew Shymanel
|
||||
Andrey Bienkowski
|
||||
Andrey Bulgakov
|
||||
Andrés Delfino
|
||||
Andy Freeland
|
||||
Andy Kluger
|
||||
Ani Hayrapetyan
|
||||
Aniruddha Basak
|
||||
Anish Tambe
|
||||
Anrs Hu
|
||||
Anthony Sottile
|
||||
Antoine Musso
|
||||
Anton Ovchinnikov
|
||||
Anton Patrushev
|
||||
Anton Zelenov
|
||||
Antonio Alvarado Hernandez
|
||||
Antony Lee
|
||||
Antti Kaihola
|
||||
Anubhav Patel
|
||||
Anudit Nagar
|
||||
Anuj Godase
|
||||
AQNOUCH Mohammed
|
||||
AraHaan
|
||||
arena
|
||||
arenasys
|
||||
Arindam Choudhury
|
||||
Armin Ronacher
|
||||
Arnon Yaari
|
||||
Artem
|
||||
Arun Babu Neelicattu
|
||||
Ashley Manton
|
||||
Ashwin Ramaswami
|
||||
atse
|
||||
Atsushi Odagiri
|
||||
Avinash Karhana
|
||||
Avner Cohen
|
||||
Awit (Ah-Wit) Ghirmai
|
||||
Baptiste Mispelon
|
||||
Barney Gale
|
||||
barneygale
|
||||
Bartek Ogryczak
|
||||
Bastian Venthur
|
||||
Ben Bodenmiller
|
||||
Ben Darnell
|
||||
Ben Hoyt
|
||||
Ben Mares
|
||||
Ben Rosser
|
||||
Bence Nagy
|
||||
Benjamin Peterson
|
||||
Benjamin VanEvery
|
||||
Benoit Pierre
|
||||
Berker Peksag
|
||||
Bernard
|
||||
Bernard Tyers
|
||||
Bernardo B. Marques
|
||||
Bernhard M. Wiedemann
|
||||
Bertil Hatt
|
||||
Bhavam Vidyarthi
|
||||
Blazej Michalik
|
||||
Bogdan Opanchuk
|
||||
BorisZZZ
|
||||
Brad Erickson
|
||||
Bradley Ayers
|
||||
Branch Vincent
|
||||
Brandon L. Reiss
|
||||
Brandt Bucher
|
||||
Brannon Dorsey
|
||||
Brett Randall
|
||||
Brett Rosen
|
||||
Brian Cristante
|
||||
Brian Rosner
|
||||
briantracy
|
||||
BrownTruck
|
||||
Bruno Oliveira
|
||||
Bruno Renié
|
||||
Bruno S
|
||||
Bstrdsmkr
|
||||
Buck Golemon
|
||||
burrows
|
||||
Bussonnier Matthias
|
||||
bwoodsend
|
||||
c22
|
||||
Caleb Martinez
|
||||
Calvin Smith
|
||||
Carl Meyer
|
||||
Carlos Liam
|
||||
Carol Willing
|
||||
Carter Thayer
|
||||
Cass
|
||||
Chandrasekhar Atina
|
||||
Charlie Marsh
|
||||
Chih-Hsuan Yen
|
||||
Chris Brinker
|
||||
Chris Hunt
|
||||
Chris Jerdonek
|
||||
Chris Kuehl
|
||||
Chris Markiewicz
|
||||
Chris McDonough
|
||||
Chris Pawley
|
||||
Chris Pryer
|
||||
Chris Wolfe
|
||||
Christian Clauss
|
||||
Christian Heimes
|
||||
Christian Oudard
|
||||
Christoph Reiter
|
||||
Christopher Hunt
|
||||
Christopher Snyder
|
||||
chrysle
|
||||
cjc7373
|
||||
Clark Boylan
|
||||
Claudio Jolowicz
|
||||
Clay McClure
|
||||
Cody
|
||||
Cody Soyland
|
||||
Colin Watson
|
||||
Collin Anderson
|
||||
Connor Osborn
|
||||
Cooper Lees
|
||||
Cooper Ry Lees
|
||||
Cory Benfield
|
||||
Cory Wright
|
||||
Craig Kerstiens
|
||||
Cristian Sorinel
|
||||
Cristina
|
||||
Cristina Muñoz
|
||||
ctg123
|
||||
Curtis Doty
|
||||
cytolentino
|
||||
Daan De Meyer
|
||||
Dale
|
||||
Damian
|
||||
Damian Quiroga
|
||||
Damian Shaw
|
||||
Dan Black
|
||||
Dan Savilonis
|
||||
Dan Sully
|
||||
Dane Hillard
|
||||
daniel
|
||||
Daniel Collins
|
||||
Daniel Hahler
|
||||
Daniel Holth
|
||||
Daniel Jost
|
||||
Daniel Katz
|
||||
Daniel Shaulov
|
||||
Daniele Esposti
|
||||
Daniele Nicolodi
|
||||
Daniele Procida
|
||||
Daniil Konovalenko
|
||||
Danny Hermes
|
||||
Danny McClanahan
|
||||
Darren Kavanagh
|
||||
Dav Clark
|
||||
Dave Abrahams
|
||||
Dave Jones
|
||||
David Aguilar
|
||||
David Black
|
||||
David Bordeynik
|
||||
David Caro
|
||||
David D Lowe
|
||||
David Evans
|
||||
David Hewitt
|
||||
David Linke
|
||||
David Poggi
|
||||
David Poznik
|
||||
David Pursehouse
|
||||
David Runge
|
||||
David Tucker
|
||||
David Wales
|
||||
Davidovich
|
||||
ddelange
|
||||
Deepak Sharma
|
||||
Deepyaman Datta
|
||||
Denise Yu
|
||||
dependabot[bot]
|
||||
derwolfe
|
||||
Desetude
|
||||
Devesh Kumar Singh
|
||||
devsagul
|
||||
Diego Caraballo
|
||||
Diego Ramirez
|
||||
DiegoCaraballo
|
||||
Dimitri Merejkowsky
|
||||
Dimitri Papadopoulos
|
||||
Dimitri Papadopoulos Orfanos
|
||||
Dirk Stolle
|
||||
Dmitry Gladkov
|
||||
Dmitry Volodin
|
||||
Domen Kožar
|
||||
Dominic Davis-Foster
|
||||
Donald Stufft
|
||||
Dongweiming
|
||||
doron zarhi
|
||||
Dos Moonen
|
||||
Douglas Thor
|
||||
DrFeathers
|
||||
Dustin Ingram
|
||||
Dustin Rodrigues
|
||||
Dwayne Bailey
|
||||
Ed Morley
|
||||
Edgar Ramírez
|
||||
Edgar Ramírez Mondragón
|
||||
Ee Durbin
|
||||
Efflam Lemaillet
|
||||
efflamlemaillet
|
||||
Eitan Adler
|
||||
ekristina
|
||||
elainechan
|
||||
Eli Schwartz
|
||||
Elisha Hollander
|
||||
Ellen Marie Dash
|
||||
Emil Burzo
|
||||
Emil Styrke
|
||||
Emmanuel Arias
|
||||
Endoh Takanao
|
||||
enoch
|
||||
Erdinc Mutlu
|
||||
Eric Cousineau
|
||||
Eric Gillingham
|
||||
Eric Hanchrow
|
||||
Eric Hopper
|
||||
Erik M. Bray
|
||||
Erik Rose
|
||||
Erwin Janssen
|
||||
Eugene Vereshchagin
|
||||
everdimension
|
||||
Federico
|
||||
Felipe Peter
|
||||
Felix Yan
|
||||
fiber-space
|
||||
Filip Kokosiński
|
||||
Filipe Laíns
|
||||
Finn Womack
|
||||
finnagin
|
||||
Flavio Amurrio
|
||||
Florian Briand
|
||||
Florian Rathgeber
|
||||
Francesco
|
||||
Francesco Montesano
|
||||
Fredrik Orderud
|
||||
Frost Ming
|
||||
Gabriel Curio
|
||||
Gabriel de Perthuis
|
||||
Garry Polley
|
||||
gavin
|
||||
gdanielson
|
||||
Geoffrey Sneddon
|
||||
George Song
|
||||
Georgi Valkov
|
||||
Georgy Pchelkin
|
||||
ghost
|
||||
Giftlin Rajaiah
|
||||
gizmoguy1
|
||||
gkdoc
|
||||
Godefroid Chapelle
|
||||
Gopinath M
|
||||
GOTO Hayato
|
||||
gousaiyang
|
||||
gpiks
|
||||
Greg Roodt
|
||||
Greg Ward
|
||||
Guilherme Espada
|
||||
Guillaume Seguin
|
||||
gutsytechster
|
||||
Guy Rozendorn
|
||||
Guy Tuval
|
||||
gzpan123
|
||||
Hanjun Kim
|
||||
Hari Charan
|
||||
Harsh Vardhan
|
||||
harupy
|
||||
Harutaka Kawamura
|
||||
hauntsaninja
|
||||
Henrich Hartzer
|
||||
Henry Schreiner
|
||||
Herbert Pfennig
|
||||
Holly Stotelmyer
|
||||
Honnix
|
||||
Hsiaoming Yang
|
||||
Hugo Lopes Tavares
|
||||
Hugo van Kemenade
|
||||
Hugues Bruant
|
||||
Hynek Schlawack
|
||||
Ian Bicking
|
||||
Ian Cordasco
|
||||
Ian Lee
|
||||
Ian Stapleton Cordasco
|
||||
Ian Wienand
|
||||
Igor Kuzmitshov
|
||||
Igor Sobreira
|
||||
Ikko Ashimine
|
||||
Ilan Schnell
|
||||
Illia Volochii
|
||||
Ilya Baryshev
|
||||
Inada Naoki
|
||||
Ionel Cristian Mărieș
|
||||
Ionel Maries Cristian
|
||||
Itamar Turner-Trauring
|
||||
Ivan Pozdeev
|
||||
J. Nick Koston
|
||||
Jacob Kim
|
||||
Jacob Walls
|
||||
Jaime Sanz
|
||||
jakirkham
|
||||
Jakub Kuczys
|
||||
Jakub Stasiak
|
||||
Jakub Vysoky
|
||||
Jakub Wilk
|
||||
James Cleveland
|
||||
James Curtin
|
||||
James Firth
|
||||
James Gerity
|
||||
James Polley
|
||||
Jan Pokorný
|
||||
Jannis Leidel
|
||||
Jarek Potiuk
|
||||
jarondl
|
||||
Jason Curtis
|
||||
Jason R. Coombs
|
||||
JasonMo
|
||||
JasonMo1
|
||||
Jay Graves
|
||||
Jean Abou Samra
|
||||
Jean-Christophe Fillion-Robin
|
||||
Jeff Barber
|
||||
Jeff Dairiki
|
||||
Jeff Widman
|
||||
Jelmer Vernooij
|
||||
jenix21
|
||||
Jeremy Fleischman
|
||||
Jeremy Stanley
|
||||
Jeremy Zafran
|
||||
Jesse Rittner
|
||||
Jiashuo Li
|
||||
Jim Fisher
|
||||
Jim Garrison
|
||||
Jinzhe Zeng
|
||||
Jiun Bae
|
||||
Jivan Amara
|
||||
Joe Bylund
|
||||
Joe Michelini
|
||||
John Paton
|
||||
John Sirois
|
||||
John T. Wodder II
|
||||
John-Scott Atlakson
|
||||
johnthagen
|
||||
Jon Banafato
|
||||
Jon Dufresne
|
||||
Jon Parise
|
||||
Jonas Nockert
|
||||
Jonathan Herbert
|
||||
Joonatan Partanen
|
||||
Joost Molenaar
|
||||
Jorge Niedbalski
|
||||
Joseph Bylund
|
||||
Joseph Long
|
||||
Josh Bronson
|
||||
Josh Cannon
|
||||
Josh Hansen
|
||||
Josh Schneier
|
||||
Joshua
|
||||
Juan Luis Cano Rodríguez
|
||||
Juanjo Bazán
|
||||
Judah Rand
|
||||
Julian Berman
|
||||
Julian Gethmann
|
||||
Julien Demoor
|
||||
Jussi Kukkonen
|
||||
jwg4
|
||||
Jyrki Pulliainen
|
||||
Kai Chen
|
||||
Kai Mueller
|
||||
Kamal Bin Mustafa
|
||||
kasium
|
||||
kaustav haldar
|
||||
keanemind
|
||||
Keith Maxwell
|
||||
Kelsey Hightower
|
||||
Kenneth Belitzky
|
||||
Kenneth Reitz
|
||||
Kevin Burke
|
||||
Kevin Carter
|
||||
Kevin Frommelt
|
||||
Kevin R Patterson
|
||||
Kexuan Sun
|
||||
Kit Randel
|
||||
Klaas van Schelven
|
||||
KOLANICH
|
||||
konstin
|
||||
kpinc
|
||||
Krishna Oza
|
||||
Kumar McMillan
|
||||
Kuntal Majumder
|
||||
Kurt McKee
|
||||
Kyle Persohn
|
||||
lakshmanaram
|
||||
Laszlo Kiss-Kollar
|
||||
Laurent Bristiel
|
||||
Laurent LAPORTE
|
||||
Laurie O
|
||||
Laurie Opperman
|
||||
layday
|
||||
Leon Sasson
|
||||
Lev Givon
|
||||
Lincoln de Sousa
|
||||
Lipis
|
||||
lorddavidiii
|
||||
Loren Carvalho
|
||||
Lucas Cimon
|
||||
Ludovic Gasc
|
||||
Luis Medel
|
||||
Lukas Geiger
|
||||
Lukas Juhrich
|
||||
Luke Macken
|
||||
Luo Jiebin
|
||||
luojiebin
|
||||
luz.paz
|
||||
László Kiss Kollár
|
||||
M00nL1ght
|
||||
Marc Abramowitz
|
||||
Marc Tamlyn
|
||||
Marcus Smith
|
||||
Mariatta
|
||||
Mark Kohler
|
||||
Mark McLoughlin
|
||||
Mark Williams
|
||||
Markus Hametner
|
||||
Martey Dodoo
|
||||
Martin Fischer
|
||||
Martin Häcker
|
||||
Martin Pavlasek
|
||||
Masaki
|
||||
Masklinn
|
||||
Matej Stuchlik
|
||||
Mathew Jennings
|
||||
Mathieu Bridon
|
||||
Mathieu Kniewallner
|
||||
Matt Bacchi
|
||||
Matt Good
|
||||
Matt Maker
|
||||
Matt Robenolt
|
||||
Matt Wozniski
|
||||
matthew
|
||||
Matthew Einhorn
|
||||
Matthew Feickert
|
||||
Matthew Gilliard
|
||||
Matthew Hughes
|
||||
Matthew Iversen
|
||||
Matthew Treinish
|
||||
Matthew Trumbell
|
||||
Matthew Willson
|
||||
Matthias Bussonnier
|
||||
mattip
|
||||
Maurits van Rees
|
||||
Max W Chase
|
||||
Maxim Kurnikov
|
||||
Maxime Rouyrre
|
||||
mayeut
|
||||
mbaluna
|
||||
mdebi
|
||||
memoselyk
|
||||
meowmeowcat
|
||||
Michael
|
||||
Michael Aquilina
|
||||
Michael E. Karpeles
|
||||
Michael Klich
|
||||
Michael Mintz
|
||||
Michael Williamson
|
||||
michaelpacer
|
||||
Michał Górny
|
||||
Mickaël Schoentgen
|
||||
Miguel Araujo Perez
|
||||
Mihir Singh
|
||||
Mike
|
||||
Mike Hendricks
|
||||
Min RK
|
||||
MinRK
|
||||
Miro Hrončok
|
||||
Monica Baluna
|
||||
montefra
|
||||
Monty Taylor
|
||||
morotti
|
||||
mrKazzila
|
||||
Muha Ajjan
|
||||
Nadav Wexler
|
||||
Nahuel Ambrosini
|
||||
Nate Coraor
|
||||
Nate Prewitt
|
||||
Nathan Houghton
|
||||
Nathaniel J. Smith
|
||||
Nehal J Wani
|
||||
Neil Botelho
|
||||
Nguyễn Gia Phong
|
||||
Nicholas Serra
|
||||
Nick Coghlan
|
||||
Nick Stenning
|
||||
Nick Timkovich
|
||||
Nicolas Bock
|
||||
Nicole Harris
|
||||
Nikhil Benesch
|
||||
Nikhil Ladha
|
||||
Nikita Chepanov
|
||||
Nikolay Korolev
|
||||
Nipunn Koorapati
|
||||
Nitesh Sharma
|
||||
Niyas Sait
|
||||
Noah
|
||||
Noah Gorny
|
||||
Nowell Strite
|
||||
NtaleGrey
|
||||
nvdv
|
||||
OBITORASU
|
||||
Ofek Lev
|
||||
ofrinevo
|
||||
Oliver Freund
|
||||
Oliver Jeeves
|
||||
Oliver Mannion
|
||||
Oliver Tonnhofer
|
||||
Olivier Girardot
|
||||
Olivier Grisel
|
||||
Ollie Rutherfurd
|
||||
OMOTO Kenji
|
||||
Omry Yadan
|
||||
onlinejudge95
|
||||
Oren Held
|
||||
Oscar Benjamin
|
||||
Oz N Tiram
|
||||
Pachwenko
|
||||
Patrick Dubroy
|
||||
Patrick Jenkins
|
||||
Patrick Lawson
|
||||
patricktokeeffe
|
||||
Patrik Kopkan
|
||||
Paul Ganssle
|
||||
Paul Kehrer
|
||||
Paul Moore
|
||||
Paul Nasrat
|
||||
Paul Oswald
|
||||
Paul van der Linden
|
||||
Paulus Schoutsen
|
||||
Pavel Safronov
|
||||
Pavithra Eswaramoorthy
|
||||
Pawel Jasinski
|
||||
Paweł Szramowski
|
||||
Pekka Klärck
|
||||
Peter Gessler
|
||||
Peter Lisák
|
||||
Peter Shen
|
||||
Peter Waller
|
||||
Petr Viktorin
|
||||
petr-tik
|
||||
Phaneendra Chiruvella
|
||||
Phil Elson
|
||||
Phil Freo
|
||||
Phil Pennock
|
||||
Phil Whelan
|
||||
Philip Jägenstedt
|
||||
Philip Molloy
|
||||
Philippe Ombredanne
|
||||
Pi Delport
|
||||
Pierre-Yves Rofes
|
||||
Pieter Degroote
|
||||
pip
|
||||
Prabakaran Kumaresshan
|
||||
Prabhjyotsing Surjit Singh Sodhi
|
||||
Prabhu Marappan
|
||||
Pradyun Gedam
|
||||
Prashant Sharma
|
||||
Pratik Mallya
|
||||
pre-commit-ci[bot]
|
||||
Preet Thakkar
|
||||
Preston Holmes
|
||||
Przemek Wrzos
|
||||
Pulkit Goyal
|
||||
q0w
|
||||
Qiangning Hong
|
||||
Qiming Xu
|
||||
Quentin Lee
|
||||
Quentin Pradet
|
||||
R. David Murray
|
||||
Rafael Caricio
|
||||
Ralf Schmitt
|
||||
Ran Benita
|
||||
Razzi Abuissa
|
||||
rdb
|
||||
Reece Dunham
|
||||
Remi Rampin
|
||||
Rene Dudfield
|
||||
Riccardo Magliocchetti
|
||||
Riccardo Schirone
|
||||
Richard Jones
|
||||
Richard Si
|
||||
Ricky Ng-Adam
|
||||
Rishi
|
||||
rmorotti
|
||||
RobberPhex
|
||||
Robert Collins
|
||||
Robert McGibbon
|
||||
Robert Pollak
|
||||
Robert T. McGibbon
|
||||
robin elisha robinson
|
||||
Roey Berman
|
||||
Rohan Jain
|
||||
Roman Bogorodskiy
|
||||
Roman Donchenko
|
||||
Romuald Brunet
|
||||
ronaudinho
|
||||
Ronny Pfannschmidt
|
||||
Rory McCann
|
||||
Ross Brattain
|
||||
Roy Wellington Ⅳ
|
||||
Ruairidh MacLeod
|
||||
Russell Keith-Magee
|
||||
Ryan Shepherd
|
||||
Ryan Wooden
|
||||
ryneeverett
|
||||
S. Guliaev
|
||||
Sachi King
|
||||
Salvatore Rinchiera
|
||||
sandeepkiran-js
|
||||
Sander Van Balen
|
||||
Savio Jomton
|
||||
schlamar
|
||||
Scott Kitterman
|
||||
Sean
|
||||
seanj
|
||||
Sebastian Jordan
|
||||
Sebastian Schaetz
|
||||
Segev Finer
|
||||
SeongSoo Cho
|
||||
Sergey Vasilyev
|
||||
Seth Michael Larson
|
||||
Seth Woodworth
|
||||
Shahar Epstein
|
||||
Shantanu
|
||||
shenxianpeng
|
||||
shireenrao
|
||||
Shivansh-007
|
||||
Shixian Sheng
|
||||
Shlomi Fish
|
||||
Shovan Maity
|
||||
Simeon Visser
|
||||
Simon Cross
|
||||
Simon Pichugin
|
||||
sinoroc
|
||||
sinscary
|
||||
snook92
|
||||
socketubs
|
||||
Sorin Sbarnea
|
||||
Srinivas Nyayapati
|
||||
Srishti Hegde
|
||||
Stavros Korokithakis
|
||||
Stefan Scherfke
|
||||
Stefano Rivera
|
||||
Stephan Erb
|
||||
Stephen Rosen
|
||||
stepshal
|
||||
Steve (Gadget) Barnes
|
||||
Steve Barnes
|
||||
Steve Dower
|
||||
Steve Kowalik
|
||||
Steven Myint
|
||||
Steven Silvester
|
||||
stonebig
|
||||
studioj
|
||||
Stéphane Bidoul
|
||||
Stéphane Bidoul (ACSONE)
|
||||
Stéphane Klein
|
||||
Sumana Harihareswara
|
||||
Surbhi Sharma
|
||||
Sviatoslav Sydorenko
|
||||
Sviatoslav Sydorenko (Святослав Сидоренко)
|
||||
Swat009
|
||||
Sylvain
|
||||
Takayuki SHIMIZUKAWA
|
||||
Taneli Hukkinen
|
||||
tbeswick
|
||||
Thiago
|
||||
Thijs Triemstra
|
||||
Thomas Fenzl
|
||||
Thomas Grainger
|
||||
Thomas Guettler
|
||||
Thomas Johansson
|
||||
Thomas Kluyver
|
||||
Thomas Smith
|
||||
Thomas VINCENT
|
||||
Tim D. Smith
|
||||
Tim Gates
|
||||
Tim Harder
|
||||
Tim Heap
|
||||
tim smith
|
||||
tinruufu
|
||||
Tobias Hermann
|
||||
Tom Forbes
|
||||
Tom Freudenheim
|
||||
Tom V
|
||||
Tomas Hrnciar
|
||||
Tomas Orsava
|
||||
Tomer Chachamu
|
||||
Tommi Enenkel | AnB
|
||||
Tomáš Hrnčiar
|
||||
Tony Beswick
|
||||
Tony Narlock
|
||||
Tony Zhaocheng Tan
|
||||
TonyBeswick
|
||||
toonarmycaptain
|
||||
Toshio Kuratomi
|
||||
toxinu
|
||||
Travis Swicegood
|
||||
Tushar Sadhwani
|
||||
Tzu-ping Chung
|
||||
Valentin Haenel
|
||||
Victor Stinner
|
||||
victorvpaulo
|
||||
Vikram - Google
|
||||
Viktor Szépe
|
||||
Ville Skyttä
|
||||
Vinay Sajip
|
||||
Vincent Philippon
|
||||
Vinicyus Macedo
|
||||
Vipul Kumar
|
||||
Vitaly Babiy
|
||||
Vladimir Fokow
|
||||
Vladimir Rutsky
|
||||
W. Trevor King
|
||||
Wil Tan
|
||||
Wilfred Hughes
|
||||
William Edwards
|
||||
William ML Leslie
|
||||
William T Olson
|
||||
William Woodruff
|
||||
Wilson Mo
|
||||
wim glenn
|
||||
Winson Luk
|
||||
Wolfgang Maier
|
||||
Wu Zhenyu
|
||||
XAMES3
|
||||
Xavier Fernandez
|
||||
Xianpeng Shen
|
||||
xoviat
|
||||
xtreak
|
||||
YAMAMOTO Takashi
|
||||
Yen Chi Hsuan
|
||||
Yeray Diaz Diaz
|
||||
Yoval P
|
||||
Yu Jian
|
||||
Yuan Jing Vincent Yan
|
||||
Yusuke Hayashi
|
||||
Zearin
|
||||
Zhiping Deng
|
||||
ziebam
|
||||
Zvezdan Petkovic
|
||||
Łukasz Langa
|
||||
Роман Донченко
|
||||
Семён Марьясин
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,20 +0,0 @@
|
||||
Copyright (c) 2008-present The pip developers (see AUTHORS.txt file)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@ -1,90 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: pip
|
||||
Version: 24.3.1
|
||||
Summary: The PyPA recommended tool for installing Python packages.
|
||||
Author-email: The pip developers <distutils-sig@python.org>
|
||||
License: MIT
|
||||
Project-URL: Homepage, https://pip.pypa.io/
|
||||
Project-URL: Documentation, https://pip.pypa.io
|
||||
Project-URL: Source, https://github.com/pypa/pip
|
||||
Project-URL: Changelog, https://pip.pypa.io/en/stable/news/
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Topic :: Software Development :: Build Tools
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE.txt
|
||||
License-File: AUTHORS.txt
|
||||
|
||||
pip - The Python Package Installer
|
||||
==================================
|
||||
|
||||
.. |pypi-version| image:: https://img.shields.io/pypi/v/pip.svg
|
||||
:target: https://pypi.org/project/pip/
|
||||
:alt: PyPI
|
||||
|
||||
.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pip
|
||||
:target: https://pypi.org/project/pip
|
||||
:alt: PyPI - Python Version
|
||||
|
||||
.. |docs-badge| image:: https://readthedocs.org/projects/pip/badge/?version=latest
|
||||
:target: https://pip.pypa.io/en/latest
|
||||
:alt: Documentation
|
||||
|
||||
|pypi-version| |python-versions| |docs-badge|
|
||||
|
||||
pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.
|
||||
|
||||
Please take a look at our documentation for how to install and use pip:
|
||||
|
||||
* `Installation`_
|
||||
* `Usage`_
|
||||
|
||||
We release updates regularly, with a new version every 3 months. Find more details in our documentation:
|
||||
|
||||
* `Release notes`_
|
||||
* `Release process`_
|
||||
|
||||
If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:
|
||||
|
||||
* `Issue tracking`_
|
||||
* `Discourse channel`_
|
||||
* `User IRC`_
|
||||
|
||||
If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:
|
||||
|
||||
* `GitHub page`_
|
||||
* `Development documentation`_
|
||||
* `Development IRC`_
|
||||
|
||||
Code of Conduct
|
||||
---------------
|
||||
|
||||
Everyone interacting in the pip project's codebases, issue trackers, chat
|
||||
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
|
||||
|
||||
.. _package installer: https://packaging.python.org/guides/tool-recommendations/
|
||||
.. _Python Package Index: https://pypi.org
|
||||
.. _Installation: https://pip.pypa.io/en/stable/installation/
|
||||
.. _Usage: https://pip.pypa.io/en/stable/
|
||||
.. _Release notes: https://pip.pypa.io/en/stable/news.html
|
||||
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
|
||||
.. _GitHub page: https://github.com/pypa/pip
|
||||
.. _Development documentation: https://pip.pypa.io/en/latest/development
|
||||
.. _Issue tracking: https://github.com/pypa/pip/issues
|
||||
.. _Discourse channel: https://discuss.python.org/c/packaging
|
||||
.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
|
||||
.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
|
||||
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
|
||||
@ -1,853 +0,0 @@
|
||||
../../Scripts/pip.exe,sha256=yAvBcsW_HIuubmDWZJy0oARyd_kEN7UBNAhIA8k2FnM,108431
|
||||
../../Scripts/pip3.13.exe,sha256=yAvBcsW_HIuubmDWZJy0oARyd_kEN7UBNAhIA8k2FnM,108431
|
||||
../../Scripts/pip3.exe,sha256=yAvBcsW_HIuubmDWZJy0oARyd_kEN7UBNAhIA8k2FnM,108431
|
||||
pip-24.3.1.dist-info/AUTHORS.txt,sha256=Cbb630k8EL9FkBzX9Vpi6hpYWrLSlh08eXodL5u0eLI,10925
|
||||
pip-24.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
pip-24.3.1.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093
|
||||
pip-24.3.1.dist-info/METADATA,sha256=V8iCNK1GYbC82PWsLMsASDh9AO4veocRlM4Pn9q2KFI,3677
|
||||
pip-24.3.1.dist-info/RECORD,,
|
||||
pip-24.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip-24.3.1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
||||
pip-24.3.1.dist-info/entry_points.txt,sha256=eeIjuzfnfR2PrhbjnbzFU6MnSS70kZLxwaHHq6M-bD0,87
|
||||
pip-24.3.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
pip/__init__.py,sha256=faXY_neeYrA_88plEhkyhwAaYeds7wu5U1iGwP24J0s,357
|
||||
pip/__main__.py,sha256=WzbhHXTbSE6gBY19mNN9m4s5o_365LOvTYSgqgbdBhE,854
|
||||
pip/__pip-runner__.py,sha256=cPPWuJ6NK_k-GzfvlejLFgwzmYUROmpAR6QC3Q-vkXQ,1450
|
||||
pip/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/__pycache__/__pip-runner__.cpython-313.pyc,,
|
||||
pip/_internal/__init__.py,sha256=MfcoOluDZ8QMCFYal04IqOJ9q6m2V7a0aOsnI-WOxUo,513
|
||||
pip/_internal/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/build_env.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/cache.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/configuration.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/exceptions.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/main.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/pyproject.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/self_outdated_check.cpython-313.pyc,,
|
||||
pip/_internal/__pycache__/wheel_builder.cpython-313.pyc,,
|
||||
pip/_internal/build_env.py,sha256=wsTPOWyPTKvUREUcO585OU01kbQufpdigY8fVHv3WIw,10584
|
||||
pip/_internal/cache.py,sha256=Jb698p5PNigRtpW5o26wQNkkUv4MnQ94mc471wL63A0,10369
|
||||
pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132
|
||||
pip/_internal/cli/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/autocompletion.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/base_command.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/cmdoptions.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/command_context.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/index_command.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/main.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/main_parser.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/parser.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/progress_bars.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/req_command.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/spinners.cpython-313.pyc,,
|
||||
pip/_internal/cli/__pycache__/status_codes.cpython-313.pyc,,
|
||||
pip/_internal/cli/autocompletion.py,sha256=Lli3Mr6aDNu7ZkJJFFvwD2-hFxNI6Avz8OwMyS5TVrs,6865
|
||||
pip/_internal/cli/base_command.py,sha256=F8nUcSM-Y-MQljJUe724-yxmc5viFXHyM_zH70NmIh4,8289
|
||||
pip/_internal/cli/cmdoptions.py,sha256=mDqBr0d0hoztbRJs-PWtcKpqNAc7khU6ZpoesZKocT8,30110
|
||||
pip/_internal/cli/command_context.py,sha256=RHgIPwtObh5KhMrd3YZTkl8zbVG-6Okml7YbFX4Ehg0,774
|
||||
pip/_internal/cli/index_command.py,sha256=-0oPTruZGkLSMrWDleZ6UtcKP3G-SImRRuhH0RfVE3o,5631
|
||||
pip/_internal/cli/main.py,sha256=BDZef-bWe9g9Jpr4OVs4dDf-845HJsKw835T7AqEnAc,2817
|
||||
pip/_internal/cli/main_parser.py,sha256=laDpsuBDl6kyfywp9eMMA9s84jfH2TJJn-vmL0GG90w,4338
|
||||
pip/_internal/cli/parser.py,sha256=VCMtduzECUV87KaHNu-xJ-wLNL82yT3x16V4XBxOAqI,10825
|
||||
pip/_internal/cli/progress_bars.py,sha256=VgydyqjZvfhqpuNcFDn00QNuA9GxRe9CKrRG8jhPuKU,2723
|
||||
pip/_internal/cli/req_command.py,sha256=DqeFhmUMs6o6Ev8qawAcOoYNdAZsfyKS0MZI5jsJYwQ,12250
|
||||
pip/_internal/cli/spinners.py,sha256=hIJ83GerdFgFCdobIA23Jggetegl_uC4Sp586nzFbPE,5118
|
||||
pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116
|
||||
pip/_internal/commands/__init__.py,sha256=5oRO9O3dM2vGuh0bFw4HOVletryrz5HHMmmPWwJrH9U,3882
|
||||
pip/_internal/commands/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/cache.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/check.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/completion.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/configuration.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/debug.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/download.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/freeze.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/hash.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/help.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/index.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/inspect.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/install.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/list.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/search.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/show.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/uninstall.cpython-313.pyc,,
|
||||
pip/_internal/commands/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/commands/cache.py,sha256=xg76_ZFEBC6zoQ3gXLRfMZJft4z2a0RwH4GEFZC6nnU,7944
|
||||
pip/_internal/commands/check.py,sha256=Hr_4eiMd9cgVDgEvjtIdw915NmL7ROIWW8enkr8slPQ,2268
|
||||
pip/_internal/commands/completion.py,sha256=HT4lD0bgsflHq2IDgYfiEdp7IGGtE7s6MgI3xn0VQEw,4287
|
||||
pip/_internal/commands/configuration.py,sha256=n98enwp6y0b5G6fiRQjaZo43FlJKYve_daMhN-4BRNc,9766
|
||||
pip/_internal/commands/debug.py,sha256=DNDRgE9YsKrbYzU0s3VKi8rHtKF4X13CJ_br_8PUXO0,6797
|
||||
pip/_internal/commands/download.py,sha256=0qB0nys6ZEPsog451lDsjL5Bx7Z97t-B80oFZKhpzKM,5273
|
||||
pip/_internal/commands/freeze.py,sha256=2Vt72BYTSm9rzue6d8dNzt8idxWK4Db6Hd-anq7GQ80,3203
|
||||
pip/_internal/commands/hash.py,sha256=EVVOuvGtoPEdFi8SNnmdqlCQrhCxV-kJsdwtdcCnXGQ,1703
|
||||
pip/_internal/commands/help.py,sha256=gcc6QDkcgHMOuAn5UxaZwAStsRBrnGSn_yxjS57JIoM,1132
|
||||
pip/_internal/commands/index.py,sha256=RAXxmJwFhVb5S1BYzb5ifX3sn9Na8v2CCVYwSMP8pao,4731
|
||||
pip/_internal/commands/inspect.py,sha256=PGrY9TRTRCM3y5Ml8Bdk8DEOXquWRfscr4DRo1LOTPc,3189
|
||||
pip/_internal/commands/install.py,sha256=iqesiLIZc6Op9uihMQFYRhAA2DQRZUxbM4z1BwXoFls,29428
|
||||
pip/_internal/commands/list.py,sha256=oiIzSjLP6__d7dIS3q0Xb5ywsaOThBWRqMyjjKzkPdM,12769
|
||||
pip/_internal/commands/search.py,sha256=fWkUQVx_gm8ebbFAlCgqtxKXT9rNahpJ-BI__3HNZpg,5626
|
||||
pip/_internal/commands/show.py,sha256=IG9L5uo8w6UA4tI_IlmaxLCoNKPa5JNJCljj3NWs0OE,7507
|
||||
pip/_internal/commands/uninstall.py,sha256=7pOR7enK76gimyxQbzxcG1OsyLXL3DvX939xmM8Fvtg,3892
|
||||
pip/_internal/commands/wheel.py,sha256=eJRhr_qoNNxWAkkdJCNiQM7CXd4E1_YyQhsqJnBPGGg,6414
|
||||
pip/_internal/configuration.py,sha256=XkAiBS0hpzsM-LF0Qu5hvPWO_Bs67-oQKRYFBuMbESs,14006
|
||||
pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858
|
||||
pip/_internal/distributions/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/distributions/__pycache__/base.cpython-313.pyc,,
|
||||
pip/_internal/distributions/__pycache__/installed.cpython-313.pyc,,
|
||||
pip/_internal/distributions/__pycache__/sdist.cpython-313.pyc,,
|
||||
pip/_internal/distributions/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/distributions/base.py,sha256=QeB9qvKXDIjLdPBDE5fMgpfGqMMCr-govnuoQnGuiF8,1783
|
||||
pip/_internal/distributions/installed.py,sha256=QinHFbWAQ8oE0pbD8MFZWkwlnfU1QYTccA1vnhrlYOU,842
|
||||
pip/_internal/distributions/sdist.py,sha256=PlcP4a6-R6c98XnOM-b6Lkb3rsvh9iG4ok8shaanrzs,6751
|
||||
pip/_internal/distributions/wheel.py,sha256=THBYfnv7VVt8mYhMYUtH13S1E7FDwtDyDfmUcl8ai0E,1317
|
||||
pip/_internal/exceptions.py,sha256=2_byISIv3kSnI_9T-Esfxrt0LnTRgcUHyxu0twsHjQY,26481
|
||||
pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30
|
||||
pip/_internal/index/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/index/__pycache__/collector.cpython-313.pyc,,
|
||||
pip/_internal/index/__pycache__/package_finder.cpython-313.pyc,,
|
||||
pip/_internal/index/__pycache__/sources.cpython-313.pyc,,
|
||||
pip/_internal/index/collector.py,sha256=RdPO0JLAlmyBWPAWYHPyRoGjz3GNAeTngCNkbGey_mE,16265
|
||||
pip/_internal/index/package_finder.py,sha256=yRC4xsyudwKnNoU6IXvNoyqYo5ScT7lB6Wa-z2eh7cs,37666
|
||||
pip/_internal/index/sources.py,sha256=lPBLK5Xiy8Q6IQMio26Wl7ocfZOKkgGklIBNyUJ23fI,8632
|
||||
pip/_internal/locations/__init__.py,sha256=UaAxeZ_f93FyouuFf4p7SXYF-4WstXuEvd3LbmPCAno,14925
|
||||
pip/_internal/locations/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/locations/__pycache__/_distutils.cpython-313.pyc,,
|
||||
pip/_internal/locations/__pycache__/_sysconfig.cpython-313.pyc,,
|
||||
pip/_internal/locations/__pycache__/base.cpython-313.pyc,,
|
||||
pip/_internal/locations/_distutils.py,sha256=x6nyVLj7X11Y4khIdf-mFlxMl2FWadtVEgeb8upc_WI,6013
|
||||
pip/_internal/locations/_sysconfig.py,sha256=IGzds60qsFneRogC-oeBaY7bEh3lPt_v47kMJChQXsU,7724
|
||||
pip/_internal/locations/base.py,sha256=RQiPi1d4FVM2Bxk04dQhXZ2PqkeljEL2fZZ9SYqIQ78,2556
|
||||
pip/_internal/main.py,sha256=r-UnUe8HLo5XFJz8inTcOOTiu_sxNhgHb6VwlGUllOI,340
|
||||
pip/_internal/metadata/__init__.py,sha256=9pU3W3s-6HtjFuYhWcLTYVmSaziklPv7k2x8p7X1GmA,4339
|
||||
pip/_internal/metadata/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/metadata/__pycache__/_json.cpython-313.pyc,,
|
||||
pip/_internal/metadata/__pycache__/base.cpython-313.pyc,,
|
||||
pip/_internal/metadata/__pycache__/pkg_resources.cpython-313.pyc,,
|
||||
pip/_internal/metadata/_json.py,sha256=P0cAJrH_mtmMZvlZ16ZXm_-izA4lpr5wy08laICuiaA,2644
|
||||
pip/_internal/metadata/base.py,sha256=ft0K5XNgI4ETqZnRv2-CtvgYiMOMAeGMAzxT-f6VLJA,25298
|
||||
pip/_internal/metadata/importlib/__init__.py,sha256=jUUidoxnHcfITHHaAWG1G2i5fdBYklv_uJcjo2x7VYE,135
|
||||
pip/_internal/metadata/importlib/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/metadata/importlib/__pycache__/_compat.cpython-313.pyc,,
|
||||
pip/_internal/metadata/importlib/__pycache__/_dists.cpython-313.pyc,,
|
||||
pip/_internal/metadata/importlib/__pycache__/_envs.cpython-313.pyc,,
|
||||
pip/_internal/metadata/importlib/_compat.py,sha256=c6av8sP8BBjAZuFSJow1iWfygUXNM3xRTCn5nqw6B9M,2796
|
||||
pip/_internal/metadata/importlib/_dists.py,sha256=anh0mLI-FYRPUhAdipd0Va3YJJc6HelCKQ0bFhY10a0,8017
|
||||
pip/_internal/metadata/importlib/_envs.py,sha256=UUB980XSrDWrMpQ1_G45i0r8Hqlg_tg3IPQ63mEqbNc,7431
|
||||
pip/_internal/metadata/pkg_resources.py,sha256=U07ETAINSGeSRBfWUG93E4tZZbaW_f7PGzEqZN0hulc,10542
|
||||
pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63
|
||||
pip/_internal/models/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/candidate.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/direct_url.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/format_control.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/index.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/installation_report.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/link.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/scheme.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/search_scope.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/selection_prefs.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/target_python.cpython-313.pyc,,
|
||||
pip/_internal/models/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/models/candidate.py,sha256=zzgFRuw_kWPjKpGw7LC0ZUMD2CQ2EberUIYs8izjdCA,753
|
||||
pip/_internal/models/direct_url.py,sha256=uBtY2HHd3TO9cKQJWh0ThvE5FRr-MWRYChRU4IG9HZE,6578
|
||||
pip/_internal/models/format_control.py,sha256=wtsQqSK9HaUiNxQEuB-C62eVimw6G4_VQFxV9-_KDBE,2486
|
||||
pip/_internal/models/index.py,sha256=tYnL8oxGi4aSNWur0mG8DAP7rC6yuha_MwJO8xw0crI,1030
|
||||
pip/_internal/models/installation_report.py,sha256=zRVZoaz-2vsrezj_H3hLOhMZCK9c7TbzWgC-jOalD00,2818
|
||||
pip/_internal/models/link.py,sha256=jHax9O-9zlSzEwjBCDkx0OXjKXwBDwOuPwn-PsR8dCs,21034
|
||||
pip/_internal/models/scheme.py,sha256=PakmHJM3e8OOWSZFtfz1Az7f1meONJnkGuQxFlt3wBE,575
|
||||
pip/_internal/models/search_scope.py,sha256=67NEnsYY84784S-MM7ekQuo9KXLH-7MzFntXjapvAo0,4531
|
||||
pip/_internal/models/selection_prefs.py,sha256=qaFfDs3ciqoXPg6xx45N1jPLqccLJw4N0s4P0PyHTQ8,2015
|
||||
pip/_internal/models/target_python.py,sha256=2XaH2rZ5ZF-K5wcJbEMGEl7SqrTToDDNkrtQ2v_v_-Q,4271
|
||||
pip/_internal/models/wheel.py,sha256=G7dND_s4ebPkEL7RJ1qCY0QhUUWIIK6AnjWgRATF5no,4539
|
||||
pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50
|
||||
pip/_internal/network/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/auth.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/cache.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/download.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/lazy_wheel.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/session.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/utils.cpython-313.pyc,,
|
||||
pip/_internal/network/__pycache__/xmlrpc.cpython-313.pyc,,
|
||||
pip/_internal/network/auth.py,sha256=D4gASjUrqoDFlSt6gQ767KAAjv6PUyJU0puDlhXNVRE,20809
|
||||
pip/_internal/network/cache.py,sha256=48A971qCzKNFvkb57uGEk7-0xaqPS0HWj2711QNTxkU,3935
|
||||
pip/_internal/network/download.py,sha256=FLOP29dPYECBiAi7eEjvAbNkyzaKNqbyjOT2m8HPW8U,6048
|
||||
pip/_internal/network/lazy_wheel.py,sha256=PBdoMoNQQIA84Fhgne38jWF52W4x_KtsHjxgv4dkRKA,7622
|
||||
pip/_internal/network/session.py,sha256=XmanBKjVwPFmh1iJ58q6TDh9xabH37gREuQJ_feuZGA,18741
|
||||
pip/_internal/network/utils.py,sha256=Inaxel-NxBu4PQWkjyErdnfewsFCcgHph7dzR1-FboY,4088
|
||||
pip/_internal/network/xmlrpc.py,sha256=sAxzOacJ-N1NXGPvap9jC3zuYWSnnv3GXtgR2-E2APA,1838
|
||||
pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/operations/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/operations/__pycache__/check.cpython-313.pyc,,
|
||||
pip/_internal/operations/__pycache__/freeze.cpython-313.pyc,,
|
||||
pip/_internal/operations/__pycache__/prepare.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/operations/build/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/build_tracker.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/metadata.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/metadata_editable.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/wheel_editable.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-313.pyc,,
|
||||
pip/_internal/operations/build/build_tracker.py,sha256=-ARW_TcjHCOX7D2NUOGntB4Fgc6b4aolsXkAK6BWL7w,4774
|
||||
pip/_internal/operations/build/metadata.py,sha256=9S0CUD8U3QqZeXp-Zyt8HxwU90lE4QrnYDgrqZDzBnc,1422
|
||||
pip/_internal/operations/build/metadata_editable.py,sha256=VLL7LvntKE8qxdhUdEJhcotFzUsOSI8NNS043xULKew,1474
|
||||
pip/_internal/operations/build/metadata_legacy.py,sha256=8i6i1QZX9m_lKPStEFsHKM0MT4a-CD408JOw99daLmo,2190
|
||||
pip/_internal/operations/build/wheel.py,sha256=sT12FBLAxDC6wyrDorh8kvcZ1jG5qInCRWzzP-UkJiQ,1075
|
||||
pip/_internal/operations/build/wheel_editable.py,sha256=yOtoH6zpAkoKYEUtr8FhzrYnkNHQaQBjWQ2HYae1MQg,1417
|
||||
pip/_internal/operations/build/wheel_legacy.py,sha256=K-6kNhmj-1xDF45ny1yheMerF0ui4EoQCLzEoHh6-tc,3045
|
||||
pip/_internal/operations/check.py,sha256=L24vRL8VWbyywdoeAhM89WCd8zLTnjIbULlKelUgIec,5912
|
||||
pip/_internal/operations/freeze.py,sha256=V59yEyCSz_YhZuhH09-6aV_zvYBMrS_IxFFNqn2QzlA,9864
|
||||
pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51
|
||||
pip/_internal/operations/install/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/operations/install/__pycache__/editable_legacy.cpython-313.pyc,,
|
||||
pip/_internal/operations/install/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/operations/install/editable_legacy.py,sha256=PoEsNEPGbIZ2yQphPsmYTKLOCMs4gv5OcCdzW124NcA,1283
|
||||
pip/_internal/operations/install/wheel.py,sha256=X5Iz9yUg5LlK5VNQ9g2ikc6dcRu8EPi_SUi5iuEDRgo,27615
|
||||
pip/_internal/operations/prepare.py,sha256=joWJwPkuqGscQgVNImLK71e9hRapwKvRCM8HclysmvU,28118
|
||||
pip/_internal/pyproject.py,sha256=rw4fwlptDp1hZgYoplwbAGwWA32sWQkp7ysf8Ju6iXc,7287
|
||||
pip/_internal/req/__init__.py,sha256=HxBFtZy_BbCclLgr26waMtpzYdO5T3vxePvpGAXSt5s,2653
|
||||
pip/_internal/req/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/req/__pycache__/constructors.cpython-313.pyc,,
|
||||
pip/_internal/req/__pycache__/req_file.cpython-313.pyc,,
|
||||
pip/_internal/req/__pycache__/req_install.cpython-313.pyc,,
|
||||
pip/_internal/req/__pycache__/req_set.cpython-313.pyc,,
|
||||
pip/_internal/req/__pycache__/req_uninstall.cpython-313.pyc,,
|
||||
pip/_internal/req/constructors.py,sha256=v1qzCN1mIldwx-nCrPc8JO4lxkm3Fv8M5RWvt8LISjc,18430
|
||||
pip/_internal/req/req_file.py,sha256=gOOJTzL-mDRPcQhjwqjDrjn4V-3rK9TnEFnU3v8RA4Q,18752
|
||||
pip/_internal/req/req_install.py,sha256=yhT98NGDoAEk03jznTJnYCznzhiMEEA2ocgsUG_dcNU,35788
|
||||
pip/_internal/req/req_set.py,sha256=j3esG0s6SzoVReX9rWn4rpYNtyET_fwxbwJPRimvRxo,2858
|
||||
pip/_internal/req/req_uninstall.py,sha256=qzDIxJo-OETWqGais7tSMCDcWbATYABT-Tid3ityF0s,23853
|
||||
pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/resolution/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/resolution/__pycache__/base.cpython-313.pyc,,
|
||||
pip/_internal/resolution/base.py,sha256=qlmh325SBVfvG6Me9gc5Nsh5sdwHBwzHBq6aEXtKsLA,583
|
||||
pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/resolution/legacy/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/resolution/legacy/__pycache__/resolver.cpython-313.pyc,,
|
||||
pip/_internal/resolution/legacy/resolver.py,sha256=3HZiJBRd1FTN6jQpI4qRO8-TbLYeIbUTS6PFvXnXs2w,24068
|
||||
pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/base.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-313.pyc,,
|
||||
pip/_internal/resolution/resolvelib/base.py,sha256=DCf669FsqyQY5uqXeePDHQY1e4QO-pBzWH8O0s9-K94,5023
|
||||
pip/_internal/resolution/resolvelib/candidates.py,sha256=5UZ1upNnmqsP-nmEZaDYxaBgCoejw_e2WVGmmAvBxXc,20001
|
||||
pip/_internal/resolution/resolvelib/factory.py,sha256=511CaUR41LqjALuFafLVfx15WRvMhxYTdjQCoSvp4gw,32661
|
||||
pip/_internal/resolution/resolvelib/found_candidates.py,sha256=9hrTyQqFvl9I7Tji79F1AxHv39Qh1rkJ_7deSHSMfQc,6383
|
||||
pip/_internal/resolution/resolvelib/provider.py,sha256=bcsFnYvlmtB80cwVdW1fIwgol8ZNr1f1VHyRTkz47SM,9935
|
||||
pip/_internal/resolution/resolvelib/reporter.py,sha256=00JtoXEkTlw0-rl_sl54d71avwOsJHt9GGHcrj5Sza0,3168
|
||||
pip/_internal/resolution/resolvelib/requirements.py,sha256=7JG4Z72e5Yk4vU0S5ulGvbqTy4FMQGYhY5zQhX9zTtY,8065
|
||||
pip/_internal/resolution/resolvelib/resolver.py,sha256=nLJOsVMEVi2gQUVJoUFKMZAeu2f7GRMjGMvNSWyz0Bc,12592
|
||||
pip/_internal/self_outdated_check.py,sha256=pkjQixuWyQ1vrVxZAaYD6SSHgXuFUnHZybXEWTkh0S0,8145
|
||||
pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_internal/utils/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/_jaraco_text.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/_log.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/appdirs.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/compat.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/compatibility_tags.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/datetime.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/deprecation.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/direct_url_helpers.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/egg_link.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/encoding.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/entrypoints.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/filesystem.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/filetypes.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/glibc.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/hashes.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/logging.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/misc.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/packaging.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/retry.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/setuptools_build.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/subprocess.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/temp_dir.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/unpacking.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/urls.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/virtualenv.cpython-313.pyc,,
|
||||
pip/_internal/utils/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_internal/utils/_jaraco_text.py,sha256=M15uUPIh5NpP1tdUGBxRau6q1ZAEtI8-XyLEETscFfE,3350
|
||||
pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015
|
||||
pip/_internal/utils/appdirs.py,sha256=swgcTKOm3daLeXTW6v5BUS2Ti2RvEnGRQYH_yDXklAo,1665
|
||||
pip/_internal/utils/compat.py,sha256=ckkFveBiYQjRWjkNsajt_oWPS57tJvE8XxoC4OIYgCY,2399
|
||||
pip/_internal/utils/compatibility_tags.py,sha256=OWq5axHpW-MEEPztGdvgADrgJPAcV9a88Rxm4Z8VBs8,6272
|
||||
pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242
|
||||
pip/_internal/utils/deprecation.py,sha256=k7Qg_UBAaaTdyq82YVARA6D7RmcGTXGv7fnfcgigj4Q,3707
|
||||
pip/_internal/utils/direct_url_helpers.py,sha256=r2MRtkVDACv9AGqYODBUC9CjwgtsUU1s68hmgfCJMtA,3196
|
||||
pip/_internal/utils/egg_link.py,sha256=0FePZoUYKv4RGQ2t6x7w5Z427wbA_Uo3WZnAkrgsuqo,2463
|
||||
pip/_internal/utils/encoding.py,sha256=qqsXDtiwMIjXMEiIVSaOjwH5YmirCaK-dIzb6-XJsL0,1169
|
||||
pip/_internal/utils/entrypoints.py,sha256=YlhLTRl2oHBAuqhc-zmL7USS67TPWVHImjeAQHreZTQ,3064
|
||||
pip/_internal/utils/filesystem.py,sha256=ajvA-q4ocliW9kPp8Yquh-4vssXbu-UKbo5FV9V4X64,4950
|
||||
pip/_internal/utils/filetypes.py,sha256=i8XAQ0eFCog26Fw9yV0Yb1ygAqKYB1w9Cz9n0fj8gZU,716
|
||||
pip/_internal/utils/glibc.py,sha256=vUkWq_1pJuzcYNcGKLlQmABoUiisK8noYY1yc8Wq4w4,3734
|
||||
pip/_internal/utils/hashes.py,sha256=XGGLL0AG8-RhWnyz87xF6MFZ--BKadHU35D47eApCKI,4972
|
||||
pip/_internal/utils/logging.py,sha256=7BFKB1uFjdxD5crM-GtwA5T2qjbQ2LPD-gJDuJeDNTg,11606
|
||||
pip/_internal/utils/misc.py,sha256=NRV0_2fFhzy1jhvInSBv4dqCmTwct8PV7Kp0m-BPRGM,23530
|
||||
pip/_internal/utils/packaging.py,sha256=iI3LH43lVNR4hWBOqF6lFsZq4aycb2j0UcHlmDmcqUg,2109
|
||||
pip/_internal/utils/retry.py,sha256=mhFbykXjhTnZfgzeuy-vl9c8nECnYn_CMtwNJX2tYzQ,1392
|
||||
pip/_internal/utils/setuptools_build.py,sha256=ouXpud-jeS8xPyTPsXJ-m34NPvK5os45otAzdSV_IJE,4435
|
||||
pip/_internal/utils/subprocess.py,sha256=EsvqSRiSMHF98T8Txmu6NLU3U--MpTTQjtNgKP0P--M,8988
|
||||
pip/_internal/utils/temp_dir.py,sha256=5qOXe8M4JeY6vaFQM867d5zkp1bSwMZ-KT5jymmP0Zg,9310
|
||||
pip/_internal/utils/unpacking.py,sha256=eyDkSsk4nW8ZfiSjNzJduCznpHyaGHVv3ak_LMGsiEM,11951
|
||||
pip/_internal/utils/urls.py,sha256=qceSOZb5lbNDrHNsv7_S4L4Ytszja5NwPKUMnZHbYnM,1599
|
||||
pip/_internal/utils/virtualenv.py,sha256=S6f7csYorRpiD6cvn3jISZYc3I8PJC43H5iMFpRAEDU,3456
|
||||
pip/_internal/utils/wheel.py,sha256=b442jkydFHjXzDy6cMR7MpzWBJ1Q82hR5F33cmcHV3g,4494
|
||||
pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596
|
||||
pip/_internal/vcs/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_internal/vcs/__pycache__/bazaar.cpython-313.pyc,,
|
||||
pip/_internal/vcs/__pycache__/git.cpython-313.pyc,,
|
||||
pip/_internal/vcs/__pycache__/mercurial.cpython-313.pyc,,
|
||||
pip/_internal/vcs/__pycache__/subversion.cpython-313.pyc,,
|
||||
pip/_internal/vcs/__pycache__/versioncontrol.cpython-313.pyc,,
|
||||
pip/_internal/vcs/bazaar.py,sha256=EKStcQaKpNu0NK4p5Q10Oc4xb3DUxFw024XrJy40bFQ,3528
|
||||
pip/_internal/vcs/git.py,sha256=3tpc9LQA_J4IVW5r5NvWaaSeDzcmJOrSFZN0J8vIKfU,18177
|
||||
pip/_internal/vcs/mercurial.py,sha256=oULOhzJ2Uie-06d1omkL-_Gc6meGaUkyogvqG9ZCyPs,5249
|
||||
pip/_internal/vcs/subversion.py,sha256=ddTugHBqHzV3ebKlU5QXHPN4gUqlyXbOx8q8NgXKvs8,11735
|
||||
pip/_internal/vcs/versioncontrol.py,sha256=cvf_-hnTAjQLXJ3d17FMNhQfcO1AcKWUF10tfrYyP-c,22440
|
||||
pip/_internal/wheel_builder.py,sha256=DL3A8LKeRj_ACp11WS5wSgASgPFqeyAeXJKdXfmaWXU,11799
|
||||
pip/_vendor/__init__.py,sha256=JYuAXvClhInxIrA2FTp5p-uuWVL7WV6-vEpTs46-Qh4,4873
|
||||
pip/_vendor/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/__pycache__/typing_extensions.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__init__.py,sha256=GiYoagwPEiJ_xR_lbwWGaoCiPtF_rz4isjfjdDAgHU4,676
|
||||
pip/_vendor/cachecontrol/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/adapter.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/cache.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/controller.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/serialize.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/_cmd.py,sha256=iist2EpzJvDVIhMAxXq8iFnTBsiZAd6iplxfmNboNyk,1737
|
||||
pip/_vendor/cachecontrol/adapter.py,sha256=fByO_Pd_EOemjWbuocvBWdN85xT0q_TBm2lxS6vD4fk,6355
|
||||
pip/_vendor/cachecontrol/cache.py,sha256=OTQj72tUf8C1uEgczdl3Gc8vkldSzsTITKtDGKMx4z8,1952
|
||||
pip/_vendor/cachecontrol/caches/__init__.py,sha256=dtrrroK5BnADR1GWjCZ19aZ0tFsMfvFBtLQQU1sp_ag,303
|
||||
pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-313.pyc,,
|
||||
pip/_vendor/cachecontrol/caches/file_cache.py,sha256=9AlmmTJc6cslb6k5z_6q0sGPHVrMj8zv-uWy-simmfE,5406
|
||||
pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=9rmqwtYu_ljVkW6_oLqbC7EaX_a8YT_yLuna-eS0dgo,1386
|
||||
pip/_vendor/cachecontrol/controller.py,sha256=o-ejGJlBmpKK8QQLyTPJj0t7siU8XVHXuV8MCybCxQ8,18575
|
||||
pip/_vendor/cachecontrol/filewrapper.py,sha256=STttGmIPBvZzt2b51dUOwoWX5crcMCpKZOisM3f5BNc,4292
|
||||
pip/_vendor/cachecontrol/heuristics.py,sha256=IYe4QmHERWsMvtxNrp920WeaIsaTTyqLB14DSheSbtY,4834
|
||||
pip/_vendor/cachecontrol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/cachecontrol/serialize.py,sha256=HQd2IllQ05HzPkVLMXTF2uX5mjEQjDBkxCqUJUODpZk,5163
|
||||
pip/_vendor/cachecontrol/wrapper.py,sha256=hsGc7g8QGQTT-4f8tgz3AM5qwScg6FO0BSdLSRdEvpU,1417
|
||||
pip/_vendor/certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94
|
||||
pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255
|
||||
pip/_vendor/certifi/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/certifi/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/_vendor/certifi/__pycache__/core.cpython-313.pyc,,
|
||||
pip/_vendor/certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427
|
||||
pip/_vendor/certifi/core.py,sha256=2SRT5rIcQChFDbe37BQa-kULxAgJ8qN6l1jfqTp4HIs,4486
|
||||
pip/_vendor/certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/distlib/__init__.py,sha256=dcwgYGYGQqAEawBXPDtIx80DO_3cOmFv8HTc8JMzknQ,625
|
||||
pip/_vendor/distlib/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/compat.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/database.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/index.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/locators.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/manifest.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/markers.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/metadata.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/resources.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/scripts.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/util.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/version.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/__pycache__/wheel.cpython-313.pyc,,
|
||||
pip/_vendor/distlib/compat.py,sha256=2jRSjRI4o-vlXeTK2BCGIUhkc6e9ZGhSsacRM5oseTw,41467
|
||||
pip/_vendor/distlib/database.py,sha256=mHy_LxiXIsIVRb-T0-idBrVLw3Ffij5teHCpbjmJ9YU,51160
|
||||
pip/_vendor/distlib/index.py,sha256=lTbw268rRhj8dw1sib3VZ_0EhSGgoJO3FKJzSFMOaeA,20797
|
||||
pip/_vendor/distlib/locators.py,sha256=oBeAZpFuPQSY09MgNnLfQGGAXXvVO96BFpZyKMuK4tM,51026
|
||||
pip/_vendor/distlib/manifest.py,sha256=3qfmAmVwxRqU1o23AlfXrQGZzh6g_GGzTAP_Hb9C5zQ,14168
|
||||
pip/_vendor/distlib/markers.py,sha256=X6sDvkFGcYS8gUW8hfsWuKEKAqhQZAJ7iXOMLxRYjYk,5164
|
||||
pip/_vendor/distlib/metadata.py,sha256=zil3sg2EUfLXVigljY2d_03IJt-JSs7nX-73fECMX2s,38724
|
||||
pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820
|
||||
pip/_vendor/distlib/scripts.py,sha256=BJliaDAZaVB7WAkwokgC3HXwLD2iWiHaVI50H7C6eG8,18608
|
||||
pip/_vendor/distlib/t32.exe,sha256=a0GV5kCoWsMutvliiCKmIgV98eRZ33wXoS-XrqvJQVs,97792
|
||||
pip/_vendor/distlib/t64-arm.exe,sha256=68TAa32V504xVBnufojh0PcenpR3U4wAqTqf-MZqbPw,182784
|
||||
pip/_vendor/distlib/t64.exe,sha256=gaYY8hy4fbkHYTTnA4i26ct8IQZzkBG2pRdy0iyuBrc,108032
|
||||
pip/_vendor/distlib/util.py,sha256=vMPGvsS4j9hF6Y9k3Tyom1aaHLb0rFmZAEyzeAdel9w,66682
|
||||
pip/_vendor/distlib/version.py,sha256=s5VIs8wBn0fxzGxWM_aA2ZZyx525HcZbMvcTlTyZ3Rg,23727
|
||||
pip/_vendor/distlib/w32.exe,sha256=R4csx3-OGM9kL4aPIzQKRo5TfmRSHZo6QWyLhDhNBks,91648
|
||||
pip/_vendor/distlib/w64-arm.exe,sha256=xdyYhKj0WDcVUOCb05blQYvzdYIKMbmJn2SZvzkcey4,168448
|
||||
pip/_vendor/distlib/w64.exe,sha256=ejGf-rojoBfXseGLpya6bFTFPWRG21X5KvU8J5iU-K0,101888
|
||||
pip/_vendor/distlib/wheel.py,sha256=DFIVguEQHCdxnSdAO0dfFsgMcvVZitg7bCOuLwZ7A_s,43979
|
||||
pip/_vendor/distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981
|
||||
pip/_vendor/distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64
|
||||
pip/_vendor/distro/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/distro/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/_vendor/distro/__pycache__/distro.cpython-313.pyc,,
|
||||
pip/_vendor/distro/distro.py,sha256=XqbefacAhDT4zr_trnbA15eY8vdK4GTghgmvUGrEM_4,49430
|
||||
pip/_vendor/distro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/idna/__init__.py,sha256=KJQN1eQBr8iIK5SKrJ47lXvxG0BJ7Lm38W4zT0v_8lk,849
|
||||
pip/_vendor/idna/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/codec.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/compat.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/core.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/idnadata.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/intranges.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/package_data.cpython-313.pyc,,
|
||||
pip/_vendor/idna/__pycache__/uts46data.cpython-313.pyc,,
|
||||
pip/_vendor/idna/codec.py,sha256=PS6m-XmdST7Wj7J7ulRMakPDt5EBJyYrT3CPtjh-7t4,3426
|
||||
pip/_vendor/idna/compat.py,sha256=0_sOEUMT4CVw9doD3vyRhX80X19PwqFoUBs7gWsFME4,321
|
||||
pip/_vendor/idna/core.py,sha256=lyhpoe2vulEaB_65xhXmoKgO-xUqFDvcwxu5hpNNO4E,12663
|
||||
pip/_vendor/idna/idnadata.py,sha256=dqRwytzkjIHMBa2R1lYvHDwACenZPt8eGVu1Y8UBE-E,78320
|
||||
pip/_vendor/idna/intranges.py,sha256=YBr4fRYuWH7kTKS2tXlFjM24ZF1Pdvcir-aywniInqg,1881
|
||||
pip/_vendor/idna/package_data.py,sha256=Tkt0KnIeyIlnHddOaz9WSkkislNgokJAuE-p5GorMqo,21
|
||||
pip/_vendor/idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/idna/uts46data.py,sha256=1KuksWqLuccPXm2uyRVkhfiFLNIhM_H2m4azCcnOqEU,206503
|
||||
pip/_vendor/msgpack/__init__.py,sha256=gsMP7JTECZNUSjvOyIbdhNOkpB9Z8BcGwabVGY2UcdQ,1077
|
||||
pip/_vendor/msgpack/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/msgpack/__pycache__/exceptions.cpython-313.pyc,,
|
||||
pip/_vendor/msgpack/__pycache__/ext.cpython-313.pyc,,
|
||||
pip/_vendor/msgpack/__pycache__/fallback.cpython-313.pyc,,
|
||||
pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081
|
||||
pip/_vendor/msgpack/ext.py,sha256=fKp00BqDLjUtZnPd70Llr138zk8JsCuSpJkkZ5S4dt8,5629
|
||||
pip/_vendor/msgpack/fallback.py,sha256=wdUWJkWX2gzfRW9BBCTOuIE1Wvrf5PtBtR8ZtY7G_EE,33175
|
||||
pip/_vendor/packaging/__init__.py,sha256=dtw2bNmWCQ9WnMoK3bk_elL1svSlikXtLpZhCFIB9SE,496
|
||||
pip/_vendor/packaging/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_elffile.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_manylinux.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_musllinux.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_parser.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_structures.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/_tokenizer.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/markers.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/metadata.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/requirements.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/specifiers.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/tags.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/utils.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/__pycache__/version.cpython-313.pyc,,
|
||||
pip/_vendor/packaging/_elffile.py,sha256=_LcJW4YNKywYsl4169B2ukKRqwxjxst_8H0FRVQKlz8,3282
|
||||
pip/_vendor/packaging/_manylinux.py,sha256=Xo4V0PZz8sbuVCbTni0t1CR0AHeir_7ib4lTmV8scD4,9586
|
||||
pip/_vendor/packaging/_musllinux.py,sha256=p9ZqNYiOItGee8KcZFeHF_YcdhVwGHdK6r-8lgixvGQ,2694
|
||||
pip/_vendor/packaging/_parser.py,sha256=s_TvTvDNK0NrM2QB3VKThdWFM4Nc0P6JnkObkl3MjpM,10236
|
||||
pip/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431
|
||||
pip/_vendor/packaging/_tokenizer.py,sha256=J6v5H7Jzvb-g81xp_2QACKwO7LxHQA6ikryMU7zXwN8,5273
|
||||
pip/_vendor/packaging/markers.py,sha256=dWKSqn5Sp-jDmOG-W3GfLHKjwhf1IsznbT71VlBoB5M,10671
|
||||
pip/_vendor/packaging/metadata.py,sha256=KINuSkJ12u-SyoKNTy_pHNGAfMUtxNvZ53qA1zAKcKI,32349
|
||||
pip/_vendor/packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/packaging/requirements.py,sha256=gYyRSAdbrIyKDY66ugIDUQjRMvxkH2ALioTmX3tnL6o,2947
|
||||
pip/_vendor/packaging/specifiers.py,sha256=HfGgfNJRvrzC759gnnoojHyiWs_DYmcw5PEh5jHH-YE,39738
|
||||
pip/_vendor/packaging/tags.py,sha256=Fo6_cit95-7QfcMb16XtI7AUiSMgdwA_hCO_9lV2pz4,21388
|
||||
pip/_vendor/packaging/utils.py,sha256=NAdYUwnlAOpkat_RthavX8a07YuVxgGL_vwrx73GSDM,5287
|
||||
pip/_vendor/packaging/version.py,sha256=wE4sSVlF-d1H6HFC1vszEe35CwTig_fh4HHIFg95hFE,16210
|
||||
pip/_vendor/pkg_resources/__init__.py,sha256=jrhDRbOubP74QuPXxd7U7Po42PH2l-LZ2XfcO7llpZ4,124463
|
||||
pip/_vendor/pkg_resources/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__init__.py,sha256=FTA6LGNm40GwNZt3gG3uLAacWvf2E_2HTmH0rAALGR8,22285
|
||||
pip/_vendor/platformdirs/__main__.py,sha256=jBJ8zb7Mpx5ebcqF83xrpO94MaeCpNGHVf9cvDN2JLg,1505
|
||||
pip/_vendor/platformdirs/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/android.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/api.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/macos.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/unix.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/version.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/__pycache__/windows.cpython-313.pyc,,
|
||||
pip/_vendor/platformdirs/android.py,sha256=xZXY9Jd46WOsxT2U6-5HsNtDZ-IQqxcEUrBLl3hYk4o,9016
|
||||
pip/_vendor/platformdirs/api.py,sha256=QBYdUac2eC521ek_y53uD1Dcq-lJX8IgSRVd4InC6uc,8996
|
||||
pip/_vendor/platformdirs/macos.py,sha256=wftsbsvq6nZ0WORXSiCrZNkRHz_WKuktl0a6mC7MFkI,5580
|
||||
pip/_vendor/platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/platformdirs/unix.py,sha256=Cci9Wqt35dAMsg6HT9nRGHSBW5obb0pR3AE1JJnsCXg,10643
|
||||
pip/_vendor/platformdirs/version.py,sha256=r7F76tZRjgQKzrpx_I0_ZMQOMU-PS7eGnHD7zEK3KB0,411
|
||||
pip/_vendor/platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125
|
||||
pip/_vendor/pygments/__init__.py,sha256=7N1oiaWulw_nCsTY4EEixYLz15pWY5u4uPAFFi-ielU,2983
|
||||
pip/_vendor/pygments/__main__.py,sha256=isIhBxLg65nLlXukG4VkMuPfNdd7gFzTZ_R_z3Q8diY,353
|
||||
pip/_vendor/pygments/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/cmdline.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/console.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/filter.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/formatter.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/lexer.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/modeline.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/plugin.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/regexopt.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/scanner.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/sphinxext.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/style.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/token.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/unistring.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/__pycache__/util.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/cmdline.py,sha256=LIVzmAunlk9sRJJp54O4KRy9GDIN4Wu13v9p9QzfGPM,23656
|
||||
pip/_vendor/pygments/console.py,sha256=yhP9UsLAVmWKVQf2446JJewkA7AiXeeTf4Ieg3Oi2fU,1718
|
||||
pip/_vendor/pygments/filter.py,sha256=_ADNPCskD8_GmodHi6_LoVgPU3Zh336aBCT5cOeTMs0,1910
|
||||
pip/_vendor/pygments/filters/__init__.py,sha256=RdedK2KWKXlKwR7cvkfr3NUj9YiZQgMgilRMFUg2jPA,40392
|
||||
pip/_vendor/pygments/filters/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatter.py,sha256=jDWBTndlBH2Z5IYZFVDnP0qn1CaTQjTWt7iAGtCnJEg,4390
|
||||
pip/_vendor/pygments/formatters/__init__.py,sha256=8No-NUs8rBTSSBJIv4hSEQt2M0cFB4hwAT0snVc2QGE,5385
|
||||
pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/groff.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/html.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/img.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/irc.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/latex.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/other.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/svg.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/formatters/_mapping.py,sha256=1Cw37FuQlNacnxRKmtlPX4nyLoX9_ttko5ZwscNUZZ4,4176
|
||||
pip/_vendor/pygments/formatters/bbcode.py,sha256=3JQLI45tcrQ_kRUMjuab6C7Hb0XUsbVWqqbSn9cMjkI,3320
|
||||
pip/_vendor/pygments/formatters/groff.py,sha256=M39k0PaSSZRnxWjqBSVPkF0mu1-Vr7bm6RsFvs-CNN4,5106
|
||||
pip/_vendor/pygments/formatters/html.py,sha256=SE2jc3YCqbMS3rZW9EAmDlAUhdVxJ52gA4dileEvCGU,35669
|
||||
pip/_vendor/pygments/formatters/img.py,sha256=MwA4xWPLOwh6j7Yc6oHzjuqSPt0M1fh5r-5BTIIUfsU,23287
|
||||
pip/_vendor/pygments/formatters/irc.py,sha256=dp1Z0l_ObJ5NFh9MhqLGg5ptG5hgJqedT2Vkutt9v0M,4981
|
||||
pip/_vendor/pygments/formatters/latex.py,sha256=XMmhOCqUKDBQtG5mGJNAFYxApqaC5puo5cMmPfK3944,19306
|
||||
pip/_vendor/pygments/formatters/other.py,sha256=56PMJOliin-rAUdnRM0i1wsV1GdUPd_dvQq0_UPfF9c,5034
|
||||
pip/_vendor/pygments/formatters/pangomarkup.py,sha256=y16U00aVYYEFpeCfGXlYBSMacG425CbfoG8oKbKegIg,2218
|
||||
pip/_vendor/pygments/formatters/rtf.py,sha256=ZT90dmcKyJboIB0mArhL7IhE467GXRN0G7QAUgG03To,11957
|
||||
pip/_vendor/pygments/formatters/svg.py,sha256=KKsiophPupHuxm0So-MsbQEWOT54IAiSF7hZPmxtKXE,7174
|
||||
pip/_vendor/pygments/formatters/terminal.py,sha256=AojNG4MlKq2L6IsC_VnXHu4AbHCBn9Otog6u45XvxeI,4674
|
||||
pip/_vendor/pygments/formatters/terminal256.py,sha256=kGkNUVo3FpwjytIDS0if79EuUoroAprcWt3igrcIqT0,11753
|
||||
pip/_vendor/pygments/lexer.py,sha256=TYHDt___gNW4axTl2zvPZff-VQi8fPaIh5OKRcVSjUM,35349
|
||||
pip/_vendor/pygments/lexers/__init__.py,sha256=pIlxyQJuu_syh9lE080cq8ceVbEVcKp0osAFU5fawJU,12115
|
||||
pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/lexers/__pycache__/python.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/lexers/_mapping.py,sha256=61-h3zr103m01OS5BUq_AfUiL9YI06Ves9ipQ7k4vr4,76097
|
||||
pip/_vendor/pygments/lexers/python.py,sha256=2J_YJrPTr_A6fJY_qKiKv0GpgPwHMrlMSeo59qN3fe4,53687
|
||||
pip/_vendor/pygments/modeline.py,sha256=gtRYZBS-CKOCDXHhGZqApboHBaZwGH8gznN3O6nuxj4,1005
|
||||
pip/_vendor/pygments/plugin.py,sha256=ioeJ3QeoJ-UQhZpY9JL7vbxsTVuwwM7BCu-Jb8nN0AU,1891
|
||||
pip/_vendor/pygments/regexopt.py,sha256=Hky4EB13rIXEHQUNkwmCrYqtIlnXDehNR3MztafZ43w,3072
|
||||
pip/_vendor/pygments/scanner.py,sha256=NDy3ofK_fHRFK4hIDvxpamG871aewqcsIb6sgTi7Fhk,3092
|
||||
pip/_vendor/pygments/sphinxext.py,sha256=iOptJBcqOGPwMEJ2p70PvwpZPIGdvdZ8dxvq6kzxDgA,7981
|
||||
pip/_vendor/pygments/style.py,sha256=rSCZWFpg1_DwFMXDU0nEVmAcBHpuQGf9RxvOPPQvKLQ,6420
|
||||
pip/_vendor/pygments/styles/__init__.py,sha256=qUk6_1z5KmT8EdJFZYgESmG6P_HJF_2vVrDD7HSCGYY,2042
|
||||
pip/_vendor/pygments/styles/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-313.pyc,,
|
||||
pip/_vendor/pygments/styles/_mapping.py,sha256=6lovFUE29tz6EsV3XYY4hgozJ7q1JL7cfO3UOlgnS8w,3312
|
||||
pip/_vendor/pygments/token.py,sha256=qZwT7LSPy5YBY3JgDjut642CCy7JdQzAfmqD9NmT5j0,6226
|
||||
pip/_vendor/pygments/unistring.py,sha256=p5c1i-HhoIhWemy9CUsaN9o39oomYHNxXll0Xfw6tEA,63208
|
||||
pip/_vendor/pygments/util.py,sha256=2tj2nS1X9_OpcuSjf8dOET2bDVZhs8cEKd_uT6-Fgg8,10031
|
||||
pip/_vendor/pyproject_hooks/__init__.py,sha256=kCehmy0UaBa9oVMD7ZIZrnswfnP3LXZ5lvnNJAL5JBM,491
|
||||
pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-313.pyc,,
|
||||
pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-313.pyc,,
|
||||
pip/_vendor/pyproject_hooks/_compat.py,sha256=by6evrYnqkisiM-MQcvOKs5bgDMzlOSgZqRHNqf04zE,138
|
||||
pip/_vendor/pyproject_hooks/_impl.py,sha256=61GJxzQip0IInhuO69ZI5GbNQ82XEDUB_1Gg5_KtUoc,11920
|
||||
pip/_vendor/pyproject_hooks/_in_process/__init__.py,sha256=9gQATptbFkelkIy0OfWFEACzqxXJMQDWCH9rBOAZVwQ,546
|
||||
pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-313.pyc,,
|
||||
pip/_vendor/pyproject_hooks/_in_process/_in_process.py,sha256=m2b34c917IW5o-Q_6TYIHlsK9lSUlNiyrITTUH_zwew,10927
|
||||
pip/_vendor/requests/__init__.py,sha256=HlB_HzhrzGtfD_aaYUwUh1zWXLZ75_YCLyit75d0Vz8,5057
|
||||
pip/_vendor/requests/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/__version__.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/_internal_utils.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/adapters.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/api.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/auth.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/certs.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/compat.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/cookies.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/exceptions.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/help.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/hooks.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/models.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/packages.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/sessions.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/status_codes.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/structures.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__pycache__/utils.cpython-313.pyc,,
|
||||
pip/_vendor/requests/__version__.py,sha256=FVfglgZmNQnmYPXpOohDU58F5EUb_-VnSTaAesS187g,435
|
||||
pip/_vendor/requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495
|
||||
pip/_vendor/requests/adapters.py,sha256=J7VeVxKBvawbtlX2DERVo05J9BXTcWYLMHNd1Baa-bk,27607
|
||||
pip/_vendor/requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449
|
||||
pip/_vendor/requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186
|
||||
pip/_vendor/requests/certs.py,sha256=PVPooB0jP5hkZEULSCwC074532UFbR2Ptgu0I5zwmCs,575
|
||||
pip/_vendor/requests/compat.py,sha256=Mo9f9xZpefod8Zm-n9_StJcVTmwSukXR2p3IQyyVXvU,1485
|
||||
pip/_vendor/requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590
|
||||
pip/_vendor/requests/exceptions.py,sha256=D1wqzYWne1mS2rU43tP9CeN1G7QAy7eqL9o1god6Ejw,4272
|
||||
pip/_vendor/requests/help.py,sha256=hRKaf9u0G7fdwrqMHtF3oG16RKktRf6KiwtSq2Fo1_0,3813
|
||||
pip/_vendor/requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733
|
||||
pip/_vendor/requests/models.py,sha256=x4K4CmH-lC0l2Kb-iPfMN4dRXxHEcbOaEWBL_i09AwI,35483
|
||||
pip/_vendor/requests/packages.py,sha256=_ZQDCJTJ8SP3kVWunSqBsRZNPzj2c1WFVqbdr08pz3U,1057
|
||||
pip/_vendor/requests/sessions.py,sha256=ykTI8UWGSltOfH07HKollH7kTBGw4WhiBVaQGmckTw4,30495
|
||||
pip/_vendor/requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322
|
||||
pip/_vendor/requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912
|
||||
pip/_vendor/requests/utils.py,sha256=L79vnFbzJ3SFLKtJwpoWe41Tozi3RlZv94pY1TFIyow,33631
|
||||
pip/_vendor/resolvelib/__init__.py,sha256=h509TdEcpb5-44JonaU3ex2TM15GVBLjM9CNCPwnTTs,537
|
||||
pip/_vendor/resolvelib/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/__pycache__/providers.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/__pycache__/reporters.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/__pycache__/resolvers.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/__pycache__/structs.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-313.pyc,,
|
||||
pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156
|
||||
pip/_vendor/resolvelib/providers.py,sha256=fuuvVrCetu5gsxPB43ERyjfO8aReS3rFQHpDgiItbs4,5871
|
||||
pip/_vendor/resolvelib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/resolvelib/reporters.py,sha256=TSbRmWzTc26w0ggsV1bxVpeWDB8QNIre6twYl7GIZBE,1601
|
||||
pip/_vendor/resolvelib/resolvers.py,sha256=G8rsLZSq64g5VmIq-lB7UcIJ1gjAxIQJmTF4REZleQ0,20511
|
||||
pip/_vendor/resolvelib/structs.py,sha256=0_1_XO8z_CLhegP3Vpf9VJ3zJcfLm0NOHRM-i0Ykz3o,4963
|
||||
pip/_vendor/rich/__init__.py,sha256=dRxjIL-SbFVY0q3IjSMrfgBTHrm1LZDgLOygVBwiYZc,6090
|
||||
pip/_vendor/rich/__main__.py,sha256=eO7Cq8JnrgG8zVoeImiAs92q3hXNMIfp0w5lMsO7Q2Y,8477
|
||||
pip/_vendor/rich/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/__main__.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_cell_widths.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_emoji_codes.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_emoji_replace.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_export_format.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_extension.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_fileno.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_inspect.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_log_render.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_loop.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_null_file.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_palettes.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_pick.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_ratio.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_spinners.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_stack.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_timer.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_win32_console.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_windows.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_windows_renderer.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/_wrap.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/abc.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/align.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/ansi.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/bar.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/box.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/cells.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/color.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/color_triplet.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/columns.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/console.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/constrain.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/containers.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/control.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/default_styles.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/diagnose.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/emoji.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/errors.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/file_proxy.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/filesize.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/highlighter.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/json.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/jupyter.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/layout.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/live.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/live_render.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/logging.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/markup.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/measure.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/padding.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/pager.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/palette.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/panel.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/pretty.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/progress.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/progress_bar.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/prompt.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/protocol.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/region.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/repr.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/rule.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/scope.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/screen.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/segment.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/spinner.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/status.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/style.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/styled.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/syntax.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/table.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/terminal_theme.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/text.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/theme.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/themes.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/traceback.cpython-313.pyc,,
|
||||
pip/_vendor/rich/__pycache__/tree.cpython-313.pyc,,
|
||||
pip/_vendor/rich/_cell_widths.py,sha256=fbmeyetEdHjzE_Vx2l1uK7tnPOhMs2X1lJfO3vsKDpA,10209
|
||||
pip/_vendor/rich/_emoji_codes.py,sha256=hu1VL9nbVdppJrVoijVshRlcRRe_v3dju3Mmd2sKZdY,140235
|
||||
pip/_vendor/rich/_emoji_replace.py,sha256=n-kcetsEUx2ZUmhQrfeMNc-teeGhpuSQ5F8VPBsyvDo,1064
|
||||
pip/_vendor/rich/_export_format.py,sha256=RI08pSrm5tBSzPMvnbTqbD9WIalaOoN5d4M1RTmLq1Y,2128
|
||||
pip/_vendor/rich/_extension.py,sha256=Xt47QacCKwYruzjDi-gOBq724JReDj9Cm9xUi5fr-34,265
|
||||
pip/_vendor/rich/_fileno.py,sha256=HWZxP5C2ajMbHryvAQZseflVfQoGzsKOHzKGsLD8ynQ,799
|
||||
pip/_vendor/rich/_inspect.py,sha256=oZJGw31e64dwXSCmrDnvZbwVb1ZKhWfU8wI3VWohjJk,9695
|
||||
pip/_vendor/rich/_log_render.py,sha256=1ByI0PA1ZpxZY3CGJOK54hjlq4X-Bz_boIjIqCd8Kns,3225
|
||||
pip/_vendor/rich/_loop.py,sha256=hV_6CLdoPm0va22Wpw4zKqM0RYsz3TZxXj0PoS-9eDQ,1236
|
||||
pip/_vendor/rich/_null_file.py,sha256=tGSXk_v-IZmbj1GAzHit8A3kYIQMiCpVsCFfsC-_KJ4,1387
|
||||
pip/_vendor/rich/_palettes.py,sha256=cdev1JQKZ0JvlguV9ipHgznTdnvlIzUFDBb0It2PzjI,7063
|
||||
pip/_vendor/rich/_pick.py,sha256=evDt8QN4lF5CiwrUIXlOJCntitBCOsI3ZLPEIAVRLJU,423
|
||||
pip/_vendor/rich/_ratio.py,sha256=Zt58apszI6hAAcXPpgdWKpu3c31UBWebOeR4mbyptvU,5471
|
||||
pip/_vendor/rich/_spinners.py,sha256=U2r1_g_1zSjsjiUdAESc2iAMc3i4ri_S8PYP6kQ5z1I,19919
|
||||
pip/_vendor/rich/_stack.py,sha256=-C8OK7rxn3sIUdVwxZBBpeHhIzX0eI-VM3MemYfaXm0,351
|
||||
pip/_vendor/rich/_timer.py,sha256=zelxbT6oPFZnNrwWPpc1ktUeAT-Vc4fuFcRZLQGLtMI,417
|
||||
pip/_vendor/rich/_win32_console.py,sha256=P0vxI2fcndym1UU1S37XAzQzQnkyY7YqAKmxm24_gug,22820
|
||||
pip/_vendor/rich/_windows.py,sha256=aBwaD_S56SbgopIvayVmpk0Y28uwY2C5Bab1wl3Bp-I,1925
|
||||
pip/_vendor/rich/_windows_renderer.py,sha256=t74ZL3xuDCP3nmTp9pH1L5LiI2cakJuQRQleHCJerlk,2783
|
||||
pip/_vendor/rich/_wrap.py,sha256=FlSsom5EX0LVkA3KWy34yHnCfLtqX-ZIepXKh-70rpc,3404
|
||||
pip/_vendor/rich/abc.py,sha256=ON-E-ZqSSheZ88VrKX2M3PXpFbGEUUZPMa_Af0l-4f0,890
|
||||
pip/_vendor/rich/align.py,sha256=sCUkisXkQfoq-IQPyBELfJ8l7LihZJX3HbH8K7Cie-M,10368
|
||||
pip/_vendor/rich/ansi.py,sha256=iD6532QYqnBm6hADulKjrV8l8kFJ-9fEVooHJHH3hMg,6906
|
||||
pip/_vendor/rich/bar.py,sha256=ldbVHOzKJOnflVNuv1xS7g6dLX2E3wMnXkdPbpzJTcs,3263
|
||||
pip/_vendor/rich/box.py,sha256=nr5fYIUghB_iUCEq6y0Z3LlCT8gFPDrzN9u2kn7tJl4,10831
|
||||
pip/_vendor/rich/cells.py,sha256=aMmGK4BjXhgE6_JF1ZEGmW3O7mKkE8g84vUnj4Et4To,4780
|
||||
pip/_vendor/rich/color.py,sha256=bCRATVdRe5IClJ6Hl62de2PKQ_U4i2MZ4ugjUEg7Tao,18223
|
||||
pip/_vendor/rich/color_triplet.py,sha256=3lhQkdJbvWPoLDO-AnYImAWmJvV5dlgYNCVZ97ORaN4,1054
|
||||
pip/_vendor/rich/columns.py,sha256=HUX0KcMm9dsKNi11fTbiM_h2iDtl8ySCaVcxlalEzq8,7131
|
||||
pip/_vendor/rich/console.py,sha256=deFZIubq2M9A2MCsKFAsFQlWDvcOMsGuUA07QkOaHIw,99173
|
||||
pip/_vendor/rich/constrain.py,sha256=1VIPuC8AgtKWrcncQrjBdYqA3JVWysu6jZo1rrh7c7Q,1288
|
||||
pip/_vendor/rich/containers.py,sha256=c_56TxcedGYqDepHBMTuZdUIijitAQgnox-Qde0Z1qo,5502
|
||||
pip/_vendor/rich/control.py,sha256=DSkHTUQLorfSERAKE_oTAEUFefZnZp4bQb4q8rHbKws,6630
|
||||
pip/_vendor/rich/default_styles.py,sha256=-Fe318kMVI_IwciK5POpThcO0-9DYJ67TZAN6DlmlmM,8082
|
||||
pip/_vendor/rich/diagnose.py,sha256=an6uouwhKPAlvQhYpNNpGq9EJysfMIOvvCbO3oSoR24,972
|
||||
pip/_vendor/rich/emoji.py,sha256=omTF9asaAnsM4yLY94eR_9dgRRSm1lHUszX20D1yYCQ,2501
|
||||
pip/_vendor/rich/errors.py,sha256=5pP3Kc5d4QJ_c0KFsxrfyhjiPVe7J1zOqSFbFAzcV-Y,642
|
||||
pip/_vendor/rich/file_proxy.py,sha256=Tl9THMDZ-Pk5Wm8sI1gGg_U5DhusmxD-FZ0fUbcU0W0,1683
|
||||
pip/_vendor/rich/filesize.py,sha256=9fTLAPCAwHmBXdRv7KZU194jSgNrRb6Wx7RIoBgqeKY,2508
|
||||
pip/_vendor/rich/highlighter.py,sha256=6ZAjUcNhBRajBCo9umFUclyi2xL0-55JL7S0vYGUJu4,9585
|
||||
pip/_vendor/rich/json.py,sha256=vVEoKdawoJRjAFayPwXkMBPLy7RSTs-f44wSQDR2nJ0,5031
|
||||
pip/_vendor/rich/jupyter.py,sha256=QyoKoE_8IdCbrtiSHp9TsTSNyTHY0FO5whE7jOTd9UE,3252
|
||||
pip/_vendor/rich/layout.py,sha256=ajkSFAtEVv9EFTcFs-w4uZfft7nEXhNzL7ZVdgrT5rI,14004
|
||||
pip/_vendor/rich/live.py,sha256=vUcnJV2LMSK3sQNaILbm0-_B8BpAeiHfcQMAMLfpRe0,14271
|
||||
pip/_vendor/rich/live_render.py,sha256=zJtB471jGziBtEwxc54x12wEQtH4BuQr1SA8v9kU82w,3666
|
||||
pip/_vendor/rich/logging.py,sha256=uB-cB-3Q4bmXDLLpbOWkmFviw-Fde39zyMV6tKJ2WHQ,11903
|
||||
pip/_vendor/rich/markup.py,sha256=3euGKP5s41NCQwaSjTnJxus5iZMHjxpIM0W6fCxra38,8451
|
||||
pip/_vendor/rich/measure.py,sha256=HmrIJX8sWRTHbgh8MxEay_83VkqNW_70s8aKP5ZcYI8,5305
|
||||
pip/_vendor/rich/padding.py,sha256=kTFGsdGe0os7tXLnHKpwTI90CXEvrceeZGCshmJy5zw,4970
|
||||
pip/_vendor/rich/pager.py,sha256=SO_ETBFKbg3n_AgOzXm41Sv36YxXAyI3_R-KOY2_uSc,828
|
||||
pip/_vendor/rich/palette.py,sha256=lInvR1ODDT2f3UZMfL1grq7dY_pDdKHw4bdUgOGaM4Y,3396
|
||||
pip/_vendor/rich/panel.py,sha256=2Fd1V7e1kHxlPFIusoHY5T7-Cs0RpkrihgVG9ZVqJ4g,10705
|
||||
pip/_vendor/rich/pretty.py,sha256=5oIHP_CGWnHEnD0zMdW5qfGC5kHqIKn7zH_eC4crULE,35848
|
||||
pip/_vendor/rich/progress.py,sha256=P02xi7T2Ua3qq17o83bkshe4c0v_45cg8VyTj6US6Vg,59715
|
||||
pip/_vendor/rich/progress_bar.py,sha256=L4jw8E6Qb_x-jhOrLVhkuMaPmiAhFIl8jHQbWFrKuR8,8164
|
||||
pip/_vendor/rich/prompt.py,sha256=wdOn2X8XTJKnLnlw6PoMY7xG4iUPp3ezt4O5gqvpV-E,11304
|
||||
pip/_vendor/rich/protocol.py,sha256=5hHHDDNHckdk8iWH5zEbi-zuIVSF5hbU2jIo47R7lTE,1391
|
||||
pip/_vendor/rich/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/rich/region.py,sha256=rNT9xZrVZTYIXZC0NYn41CJQwYNbR-KecPOxTgQvB8Y,166
|
||||
pip/_vendor/rich/repr.py,sha256=5MZJZmONgC6kud-QW-_m1okXwL2aR6u6y-pUcUCJz28,4431
|
||||
pip/_vendor/rich/rule.py,sha256=0fNaS_aERa3UMRc3T5WMpN_sumtDxfaor2y3of1ftBk,4602
|
||||
pip/_vendor/rich/scope.py,sha256=TMUU8qo17thyqQCPqjDLYpg_UU1k5qVd-WwiJvnJVas,2843
|
||||
pip/_vendor/rich/screen.py,sha256=YoeReESUhx74grqb0mSSb9lghhysWmFHYhsbMVQjXO8,1591
|
||||
pip/_vendor/rich/segment.py,sha256=hU1ueeXqI6YeFa08K9DAjlF2QLxcJY9pwZx7RsXavlk,24246
|
||||
pip/_vendor/rich/spinner.py,sha256=15koCmF0DQeD8-k28Lpt6X_zJQUlzEhgo_6A6uy47lc,4339
|
||||
pip/_vendor/rich/status.py,sha256=kkPph3YeAZBo-X-4wPp8gTqZyU466NLwZBA4PZTTewo,4424
|
||||
pip/_vendor/rich/style.py,sha256=3hiocH_4N8vwRm3-8yFWzM7tSwjjEven69XqWasSQwM,27073
|
||||
pip/_vendor/rich/styled.py,sha256=eZNnzGrI4ki_54pgY3Oj0T-x3lxdXTYh4_ryDB24wBU,1258
|
||||
pip/_vendor/rich/syntax.py,sha256=TnZDuOD4DeHFbkaVEAji1gf8qgAlMU9Boe_GksMGCkk,35475
|
||||
pip/_vendor/rich/table.py,sha256=nGEvAZHF4dy1vT9h9Gj9O5qhSQO3ODAxJv0RY1vnIB8,39680
|
||||
pip/_vendor/rich/terminal_theme.py,sha256=1j5-ufJfnvlAo5Qsi_ACZiXDmwMXzqgmFByObT9-yJY,3370
|
||||
pip/_vendor/rich/text.py,sha256=5rQ3zvNrg5UZKNLecbh7fiw9v3HeFulNVtRY_CBDjjE,47312
|
||||
pip/_vendor/rich/theme.py,sha256=belFJogzA0W0HysQabKaHOc3RWH2ko3fQAJhoN-AFdo,3777
|
||||
pip/_vendor/rich/themes.py,sha256=0xgTLozfabebYtcJtDdC5QkX5IVUEaviqDUJJh4YVFk,102
|
||||
pip/_vendor/rich/traceback.py,sha256=CUpxYLjQWIb6vQQ6O72X0hvDV6caryGqU6UweHgOyCY,29601
|
||||
pip/_vendor/rich/tree.py,sha256=meAOUU6sYnoBEOX2ILrPLY9k5bWrWNQKkaiEFvHinXM,9167
|
||||
pip/_vendor/tomli/__init__.py,sha256=JhUwV66DB1g4Hvt1UQCVMdfCu-IgAV8FXmvDU9onxd4,396
|
||||
pip/_vendor/tomli/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/tomli/__pycache__/_parser.cpython-313.pyc,,
|
||||
pip/_vendor/tomli/__pycache__/_re.cpython-313.pyc,,
|
||||
pip/_vendor/tomli/__pycache__/_types.cpython-313.pyc,,
|
||||
pip/_vendor/tomli/_parser.py,sha256=g9-ENaALS-B8dokYpCuzUFalWlog7T-SIYMjLZSWrtM,22633
|
||||
pip/_vendor/tomli/_re.py,sha256=dbjg5ChZT23Ka9z9DHOXfdtSpPwUfdgMXnj8NOoly-w,2943
|
||||
pip/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
|
||||
pip/_vendor/tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
|
||||
pip/_vendor/truststore/__init__.py,sha256=WIDeyzWm7EVX44g354M25vpRXbeY1lsPH6EmUJUcq4o,1264
|
||||
pip/_vendor/truststore/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/__pycache__/_api.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/__pycache__/_macos.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/__pycache__/_openssl.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/__pycache__/_windows.cpython-313.pyc,,
|
||||
pip/_vendor/truststore/_api.py,sha256=GeXRNTlxPZ3kif4kNoh6JY0oE4QRzTGcgXr6l_X_Gk0,10555
|
||||
pip/_vendor/truststore/_macos.py,sha256=nZlLkOmszUE0g6ryRwBVGY5COzPyudcsiJtDWarM5LQ,20503
|
||||
pip/_vendor/truststore/_openssl.py,sha256=LLUZ7ZGaio-i5dpKKjKCSeSufmn6T8pi9lDcFnvSyq0,2324
|
||||
pip/_vendor/truststore/_ssl_constants.py,sha256=NUD4fVKdSD02ri7-db0tnO0VqLP9aHuzmStcW7tAl08,1130
|
||||
pip/_vendor/truststore/_windows.py,sha256=rAHyKYD8M7t-bXfG8VgOVa3TpfhVhbt4rZQlO45YuP8,17993
|
||||
pip/_vendor/truststore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/typing_extensions.py,sha256=78hFl0HpDY-ylHUVCnWdU5nTHxUP2-S-3wEZk6CQmLk,134499
|
||||
pip/_vendor/urllib3/__init__.py,sha256=iXLcYiJySn0GNbWOOZDDApgBL1JgP44EZ8i1760S8Mc,3333
|
||||
pip/_vendor/urllib3/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/_collections.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/_version.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/connection.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/connectionpool.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/exceptions.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/fields.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/filepost.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/poolmanager.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/request.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/__pycache__/response.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/_collections.py,sha256=pyASJJhW7wdOpqJj9QJA8FyGRfr8E8uUUhqUvhF0728,11372
|
||||
pip/_vendor/urllib3/_version.py,sha256=t9wGB6ooOTXXgiY66K1m6BZS1CJyXHAU8EoWDTe6Shk,64
|
||||
pip/_vendor/urllib3/connection.py,sha256=ttIA909BrbTUzwkqEe_TzZVh4JOOj7g61Ysei2mrwGg,20314
|
||||
pip/_vendor/urllib3/connectionpool.py,sha256=e2eiAwNbFNCKxj4bwDKNK-w7HIdSz3OmMxU_TIt-evQ,40408
|
||||
pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957
|
||||
pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=4Xk64qIkPBt09A5q-RIFUuDhNc9mXilVapm7WnYnzRw,17632
|
||||
pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=B2JBB2_NRP02xK6DCa1Pa9IuxrPwxzDzZbixQkb7U9M,13922
|
||||
pip/_vendor/urllib3/contrib/appengine.py,sha256=VR68eAVE137lxTgjBDwCna5UiBZTOKa01Aj_-5BaCz4,11036
|
||||
pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=NlfkW7WMdW8ziqudopjHoW299og1BTWi0IeIibquFwk,4528
|
||||
pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=hDJh4MhyY_p-oKlFcYcQaVQRDv6GMmBGuW9yjxyeejM,17081
|
||||
pip/_vendor/urllib3/contrib/securetransport.py,sha256=Fef1IIUUFHqpevzXiDPbIGkDKchY2FVKeVeLGR1Qq3g,34446
|
||||
pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097
|
||||
pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217
|
||||
pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579
|
||||
pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440
|
||||
pip/_vendor/urllib3/packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/packages/__pycache__/six.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417
|
||||
pip/_vendor/urllib3/packages/backports/weakref_finalize.py,sha256=tRCal5OAhNSRyb0DhHp-38AtIlCsRP8BxF3NX-6rqIA,5343
|
||||
pip/_vendor/urllib3/packages/six.py,sha256=b9LM0wBXv7E7SrbCjAm4wwN-hrH-iNxv18LgWNMMKPo,34665
|
||||
pip/_vendor/urllib3/poolmanager.py,sha256=aWyhXRtNO4JUnCSVVqKTKQd8EXTvUm1VN9pgs2bcONo,19990
|
||||
pip/_vendor/urllib3/request.py,sha256=YTWFNr7QIwh7E1W9dde9LM77v2VWTJ5V78XuTTw7D1A,6691
|
||||
pip/_vendor/urllib3/response.py,sha256=fmDJAFkG71uFTn-sVSTh2Iw0WmcXQYqkbRjihvwBjU8,30641
|
||||
pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155
|
||||
pip/_vendor/urllib3/util/__pycache__/__init__.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/connection.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/proxy.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/queue.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/request.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/response.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/retry.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/timeout.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/url.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/__pycache__/wait.cpython-313.pyc,,
|
||||
pip/_vendor/urllib3/util/connection.py,sha256=5Lx2B1PW29KxBn2T0xkN1CBgRBa3gGVJBKoQoRogEVk,4901
|
||||
pip/_vendor/urllib3/util/proxy.py,sha256=zUvPPCJrp6dOF0N4GAVbOcl6o-4uXKSrGiTkkr5vUS4,1605
|
||||
pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498
|
||||
pip/_vendor/urllib3/util/request.py,sha256=C0OUt2tcU6LRiQJ7YYNP9GvPrSvl7ziIBekQ-5nlBZk,3997
|
||||
pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510
|
||||
pip/_vendor/urllib3/util/retry.py,sha256=6ENvOZ8PBDzh8kgixpql9lIrb2dxH-k7ZmBanJF2Ng4,22050
|
||||
pip/_vendor/urllib3/util/ssl_.py,sha256=QDuuTxPSCj1rYtZ4xpD7Ux-r20TD50aHyqKyhQ7Bq4A,17460
|
||||
pip/_vendor/urllib3/util/ssl_match_hostname.py,sha256=Ir4cZVEjmAk8gUAIHWSi7wtOO83UCYABY2xFD1Ql_WA,5758
|
||||
pip/_vendor/urllib3/util/ssltransport.py,sha256=NA-u5rMTrDFDFC8QzRKUEKMG0561hOD4qBTr3Z4pv6E,6895
|
||||
pip/_vendor/urllib3/util/timeout.py,sha256=cwq4dMk87mJHSBktK1miYJ-85G-3T3RmT20v7SFCpno,10168
|
||||
pip/_vendor/urllib3/util/url.py,sha256=lCAE7M5myA8EDdW0sJuyyZhVB9K_j38ljWhHAnFaWoE,14296
|
||||
pip/_vendor/urllib3/util/wait.py,sha256=fOX0_faozG2P7iVojQoE1mbydweNyTcm-hXEfFrTtLI,5403
|
||||
pip/_vendor/vendor.txt,sha256=43152uDtpsunEE29vmLqqKZUosdrbvzIFkzscLB55Cg,332
|
||||
pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.2.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
[console_scripts]
|
||||
pip = pip._internal.cli.main:main
|
||||
pip3 = pip._internal.cli.main:main
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,6 +1,6 @@
|
||||
from typing import List, Optional
|
||||
|
||||
__version__ = "24.3.1"
|
||||
__version__ = "25.0.1"
|
||||
|
||||
|
||||
def main(args: Optional[List[str]] = None) -> int:
|
||||
|
||||
@ -11,7 +11,6 @@ from collections import OrderedDict
|
||||
from types import TracebackType
|
||||
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type, Union
|
||||
|
||||
from pip._vendor.certifi import where
|
||||
from pip._vendor.packaging.version import Version
|
||||
|
||||
from pip import __file__ as pip_location
|
||||
@ -270,21 +269,25 @@ class BuildEnvironment:
|
||||
for link in finder.find_links:
|
||||
args.extend(["--find-links", link])
|
||||
|
||||
if finder.proxy:
|
||||
args.extend(["--proxy", finder.proxy])
|
||||
for host in finder.trusted_hosts:
|
||||
args.extend(["--trusted-host", host])
|
||||
if finder.custom_cert:
|
||||
args.extend(["--cert", finder.custom_cert])
|
||||
if finder.client_cert:
|
||||
args.extend(["--client-cert", finder.client_cert])
|
||||
if finder.allow_all_prereleases:
|
||||
args.append("--pre")
|
||||
if finder.prefer_binary:
|
||||
args.append("--prefer-binary")
|
||||
args.append("--")
|
||||
args.extend(requirements)
|
||||
extra_environ = {"_PIP_STANDALONE_CERT": where()}
|
||||
with open_spinner(f"Installing {kind}") as spinner:
|
||||
call_subprocess(
|
||||
args,
|
||||
command_desc=f"pip subprocess to install {kind}",
|
||||
spinner=spinner,
|
||||
extra_environ=extra_environ,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ from pip._internal.exceptions import (
|
||||
NetworkConnectionError,
|
||||
PreviousBuildDirError,
|
||||
)
|
||||
from pip._internal.utils.deprecation import deprecated
|
||||
from pip._internal.utils.filesystem import check_path_owner
|
||||
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
|
||||
from pip._internal.utils.misc import get_prog, normalize_path
|
||||
@ -228,4 +229,12 @@ class Command(CommandContextMixIn):
|
||||
)
|
||||
options.cache_dir = None
|
||||
|
||||
if options.no_python_version_warning:
|
||||
deprecated(
|
||||
reason="--no-python-version-warning is deprecated.",
|
||||
replacement="to remove the flag as it's a no-op",
|
||||
gone_in="25.1",
|
||||
issue=13154,
|
||||
)
|
||||
|
||||
return self._run_wrapper(level_number, options, args)
|
||||
|
||||
@ -260,8 +260,8 @@ keyring_provider: Callable[..., Option] = partial(
|
||||
default="auto",
|
||||
help=(
|
||||
"Enable the credential lookup via the keyring library if user input is allowed."
|
||||
" Specify which mechanism to use [disabled, import, subprocess]."
|
||||
" (default: disabled)"
|
||||
" Specify which mechanism to use [auto, disabled, import, subprocess]."
|
||||
" (default: %default)"
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -123,6 +123,7 @@ class SessionCommandMixin(CommandContextMixIn):
|
||||
"https": options.proxy,
|
||||
}
|
||||
session.trust_env = False
|
||||
session.pip_proxy = options.proxy
|
||||
|
||||
# Determine if we can prompt the user for authentication or not
|
||||
session.auth.prompting = not options.no_input
|
||||
|
||||
@ -63,7 +63,7 @@ def _raw_progress_bar(
|
||||
size: Optional[int],
|
||||
) -> Generator[bytes, None, None]:
|
||||
def write_progress(current: int, total: int) -> None:
|
||||
sys.stdout.write("Progress %d of %d\n" % (current, total))
|
||||
sys.stdout.write(f"Progress {current} of {total}\n")
|
||||
sys.stdout.flush()
|
||||
|
||||
current = 0
|
||||
|
||||
@ -8,6 +8,7 @@ from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||
from pip._internal.exceptions import CommandError, PipError
|
||||
from pip._internal.utils import filesystem
|
||||
from pip._internal.utils.logging import getLogger
|
||||
from pip._internal.utils.misc import format_size
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
@ -180,10 +181,12 @@ class CacheCommand(Command):
|
||||
if not files:
|
||||
logger.warning(no_matching_msg)
|
||||
|
||||
bytes_removed = 0
|
||||
for filename in files:
|
||||
bytes_removed += os.stat(filename).st_size
|
||||
os.unlink(filename)
|
||||
logger.verbose("Removed %s", filename)
|
||||
logger.info("Files removed: %s", len(files))
|
||||
logger.info("Files removed: %s (%s)", len(files), format_size(bytes_removed))
|
||||
|
||||
def purge_cache(self, options: Values, args: List[Any]) -> None:
|
||||
if args:
|
||||
|
||||
@ -10,6 +10,13 @@ from typing import List, Optional
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.rich import print_json
|
||||
|
||||
# Eagerly import self_outdated_check to avoid crashes. Otherwise,
|
||||
# this module would be imported *after* pip was replaced, resulting
|
||||
# in crashes if the new self_outdated_check module was incompatible
|
||||
# with the rest of pip that's already imported, or allowing a
|
||||
# wheel to execute arbitrary code on install by replacing
|
||||
# self_outdated_check.
|
||||
import pip._internal.self_outdated_check # noqa: F401
|
||||
from pip._internal.cache import WheelCache
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.cmdoptions import make_target_python
|
||||
@ -408,12 +415,6 @@ class InstallCommand(RequirementCommand):
|
||||
# If we're not replacing an already installed pip,
|
||||
# we're not modifying it.
|
||||
modifying_pip = pip_req.satisfied_by is None
|
||||
if modifying_pip:
|
||||
# Eagerly import this module to avoid crashes. Otherwise, this
|
||||
# module would be imported *after* pip was replaced, resulting in
|
||||
# crashes if the new self_outdated_check module was incompatible
|
||||
# with the rest of pip that's already imported.
|
||||
import pip._internal.self_outdated_check # noqa: F401
|
||||
protect_pip_from_modification_on_windows(modifying_pip=modifying_pip)
|
||||
|
||||
reqs_to_build = [
|
||||
@ -432,7 +433,7 @@ class InstallCommand(RequirementCommand):
|
||||
|
||||
if build_failures:
|
||||
raise InstallationError(
|
||||
"ERROR: Failed to build installable wheels for some "
|
||||
"Failed to build installable wheels for some "
|
||||
"pyproject.toml based projects ({})".format(
|
||||
", ".join(r.name for r in build_failures) # type: ignore
|
||||
)
|
||||
|
||||
@ -66,6 +66,7 @@ class _PackageInfo(NamedTuple):
|
||||
author: str
|
||||
author_email: str
|
||||
license: str
|
||||
license_expression: str
|
||||
entry_points: List[str]
|
||||
files: Optional[List[str]]
|
||||
|
||||
@ -161,6 +162,7 @@ def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None
|
||||
author=metadata.get("Author", ""),
|
||||
author_email=metadata.get("Author-email", ""),
|
||||
license=metadata.get("License", ""),
|
||||
license_expression=metadata.get("License-Expression", ""),
|
||||
entry_points=entry_points,
|
||||
files=files,
|
||||
)
|
||||
@ -180,13 +182,18 @@ def print_results(
|
||||
if i > 0:
|
||||
write_output("---")
|
||||
|
||||
metadata_version_tuple = tuple(map(int, dist.metadata_version.split(".")))
|
||||
|
||||
write_output("Name: %s", dist.name)
|
||||
write_output("Version: %s", dist.version)
|
||||
write_output("Summary: %s", dist.summary)
|
||||
write_output("Home-page: %s", dist.homepage)
|
||||
write_output("Author: %s", dist.author)
|
||||
write_output("Author-email: %s", dist.author_email)
|
||||
write_output("License: %s", dist.license)
|
||||
if metadata_version_tuple >= (2, 4) and dist.license_expression:
|
||||
write_output("License-Expression: %s", dist.license_expression)
|
||||
else:
|
||||
write_output("License: %s", dist.license)
|
||||
write_output("Location: %s", dist.location)
|
||||
if dist.editable_project_location is not None:
|
||||
write_output(
|
||||
|
||||
@ -330,7 +330,7 @@ class Configuration:
|
||||
This should be treated like items of a dictionary. The order
|
||||
here doesn't affect what gets overridden. That is controlled
|
||||
by OVERRIDE_ORDER. However this does control the order they are
|
||||
displayed to the user. It's probably most ergononmic to display
|
||||
displayed to the user. It's probably most ergonomic to display
|
||||
things in the same order as OVERRIDE_ORDER
|
||||
"""
|
||||
# SMELL: Move the conditions out of this function
|
||||
|
||||
@ -334,44 +334,30 @@ class CandidatePreferences:
|
||||
allow_all_prereleases: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BestCandidateResult:
|
||||
"""A collection of candidates, returned by `PackageFinder.find_best_candidate`.
|
||||
|
||||
This class is only intended to be instantiated by CandidateEvaluator's
|
||||
`compute_best_candidate()` method.
|
||||
|
||||
:param all_candidates: A sequence of all available candidates found.
|
||||
:param applicable_candidates: The applicable candidates.
|
||||
:param best_candidate: The most preferred candidate found, or None
|
||||
if no applicable candidates were found.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
candidates: List[InstallationCandidate],
|
||||
applicable_candidates: List[InstallationCandidate],
|
||||
best_candidate: Optional[InstallationCandidate],
|
||||
) -> None:
|
||||
"""
|
||||
:param candidates: A sequence of all available candidates found.
|
||||
:param applicable_candidates: The applicable candidates.
|
||||
:param best_candidate: The most preferred candidate found, or None
|
||||
if no applicable candidates were found.
|
||||
"""
|
||||
assert set(applicable_candidates) <= set(candidates)
|
||||
all_candidates: List[InstallationCandidate]
|
||||
applicable_candidates: List[InstallationCandidate]
|
||||
best_candidate: Optional[InstallationCandidate]
|
||||
|
||||
if best_candidate is None:
|
||||
assert not applicable_candidates
|
||||
def __post_init__(self) -> None:
|
||||
assert set(self.applicable_candidates) <= set(self.all_candidates)
|
||||
|
||||
if self.best_candidate is None:
|
||||
assert not self.applicable_candidates
|
||||
else:
|
||||
assert best_candidate in applicable_candidates
|
||||
|
||||
self._applicable_candidates = applicable_candidates
|
||||
self._candidates = candidates
|
||||
|
||||
self.best_candidate = best_candidate
|
||||
|
||||
def iter_all(self) -> Iterable[InstallationCandidate]:
|
||||
"""Iterate through all candidates."""
|
||||
return iter(self._candidates)
|
||||
|
||||
def iter_applicable(self) -> Iterable[InstallationCandidate]:
|
||||
"""Iterate through the applicable candidates."""
|
||||
return iter(self._applicable_candidates)
|
||||
assert self.best_candidate in self.applicable_candidates
|
||||
|
||||
|
||||
class CandidateEvaluator:
|
||||
@ -675,11 +661,29 @@ class PackageFinder:
|
||||
def index_urls(self) -> List[str]:
|
||||
return self.search_scope.index_urls
|
||||
|
||||
@property
|
||||
def proxy(self) -> Optional[str]:
|
||||
return self._link_collector.session.pip_proxy
|
||||
|
||||
@property
|
||||
def trusted_hosts(self) -> Iterable[str]:
|
||||
for host_port in self._link_collector.session.pip_trusted_origins:
|
||||
yield build_netloc(*host_port)
|
||||
|
||||
@property
|
||||
def custom_cert(self) -> Optional[str]:
|
||||
# session.verify is either a boolean (use default bundle/no SSL
|
||||
# verification) or a string path to a custom CA bundle to use. We only
|
||||
# care about the latter.
|
||||
verify = self._link_collector.session.verify
|
||||
return verify if isinstance(verify, str) else None
|
||||
|
||||
@property
|
||||
def client_cert(self) -> Optional[str]:
|
||||
cert = self._link_collector.session.cert
|
||||
assert not isinstance(cert, tuple), "pip only supports PEM client certs"
|
||||
return cert
|
||||
|
||||
@property
|
||||
def allow_all_prereleases(self) -> bool:
|
||||
return self._candidate_prefs.allow_all_prereleases
|
||||
@ -732,6 +736,11 @@ class PackageFinder:
|
||||
return no_eggs + eggs
|
||||
|
||||
def _log_skipped_link(self, link: Link, result: LinkType, detail: str) -> None:
|
||||
# This is a hot method so don't waste time hashing links unless we're
|
||||
# actually going to log 'em.
|
||||
if not logger.isEnabledFor(logging.DEBUG):
|
||||
return
|
||||
|
||||
entry = (link, result, detail)
|
||||
if entry not in self._logged_links:
|
||||
# Put the link at the end so the reason is more visible and because
|
||||
@ -929,7 +938,7 @@ class PackageFinder:
|
||||
"Could not find a version that satisfies the requirement %s "
|
||||
"(from versions: %s)",
|
||||
req,
|
||||
_format_versions(best_candidate_result.iter_all()),
|
||||
_format_versions(best_candidate_result.all_candidates),
|
||||
)
|
||||
|
||||
raise DistributionNotFound(f"No matching distribution found for {req}")
|
||||
@ -963,7 +972,7 @@ class PackageFinder:
|
||||
logger.debug(
|
||||
"Using version %s (newest of versions: %s)",
|
||||
best_candidate.version,
|
||||
_format_versions(best_candidate_result.iter_applicable()),
|
||||
_format_versions(best_candidate_result.applicable_candidates),
|
||||
)
|
||||
return best_candidate
|
||||
|
||||
@ -971,7 +980,7 @@ class PackageFinder:
|
||||
logger.debug(
|
||||
"Installed version (%s) is most up-to-date (past versions: %s)",
|
||||
installed_version,
|
||||
_format_versions(best_candidate_result.iter_applicable()),
|
||||
_format_versions(best_candidate_result.applicable_candidates),
|
||||
)
|
||||
raise BestVersionAlreadyInstalled
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ def _should_use_importlib_metadata() -> bool:
|
||||
"""Whether to use the ``importlib.metadata`` or ``pkg_resources`` backend.
|
||||
|
||||
By default, pip uses ``importlib.metadata`` on Python 3.11+, and
|
||||
``pkg_resourcess`` otherwise. This can be overridden by a couple of ways:
|
||||
``pkg_resources`` otherwise. This can be overridden by a couple of ways:
|
||||
|
||||
* If environment variable ``_PIP_USE_IMPORTLIB_METADATA`` is set, it
|
||||
dictates whether ``importlib.metadata`` is used, regardless of Python
|
||||
@ -71,7 +71,7 @@ def get_default_environment() -> BaseEnvironment:
|
||||
|
||||
This returns an Environment instance from the chosen backend. The default
|
||||
Environment instance should be built from ``sys.path`` and may use caching
|
||||
to share instance state accorss calls.
|
||||
to share instance state across calls.
|
||||
"""
|
||||
return select_backend().Environment.default()
|
||||
|
||||
|
||||
@ -23,6 +23,8 @@ METADATA_FIELDS = [
|
||||
("Maintainer", False),
|
||||
("Maintainer-email", False),
|
||||
("License", False),
|
||||
("License-Expression", False),
|
||||
("License-File", True),
|
||||
("Classifier", True),
|
||||
("Requires-Dist", True),
|
||||
("Requires-Python", False),
|
||||
|
||||
@ -2,6 +2,7 @@ import email.message
|
||||
import importlib.metadata
|
||||
import pathlib
|
||||
import zipfile
|
||||
from os import PathLike
|
||||
from typing import (
|
||||
Collection,
|
||||
Dict,
|
||||
@ -10,6 +11,7 @@ from typing import (
|
||||
Mapping,
|
||||
Optional,
|
||||
Sequence,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
|
||||
@ -95,6 +97,11 @@ class WheelDistribution(importlib.metadata.Distribution):
|
||||
raise UnsupportedWheel(error)
|
||||
return text
|
||||
|
||||
def locate_file(self, path: Union[str, "PathLike[str]"]) -> pathlib.Path:
|
||||
# This method doesn't make sense for our in-memory wheel, but the API
|
||||
# requires us to define it.
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Distribution(BaseDistribution):
|
||||
def __init__(
|
||||
@ -190,7 +197,7 @@ class Distribution(BaseDistribution):
|
||||
return content
|
||||
|
||||
def iter_entry_points(self) -> Iterable[BaseEntryPoint]:
|
||||
# importlib.metadata's EntryPoint structure sasitfies BaseEntryPoint.
|
||||
# importlib.metadata's EntryPoint structure satisfies BaseEntryPoint.
|
||||
return self._dist.entry_points
|
||||
|
||||
def _metadata_impl(self) -> email.message.Message:
|
||||
|
||||
@ -170,12 +170,23 @@ def _ensure_quoted_url(url: str) -> str:
|
||||
and without double-quoting other characters.
|
||||
"""
|
||||
# Split the URL into parts according to the general structure
|
||||
# `scheme://netloc/path;parameters?query#fragment`.
|
||||
result = urllib.parse.urlparse(url)
|
||||
# `scheme://netloc/path?query#fragment`.
|
||||
result = urllib.parse.urlsplit(url)
|
||||
# If the netloc is empty, then the URL refers to a local filesystem path.
|
||||
is_local_path = not result.netloc
|
||||
path = _clean_url_path(result.path, is_local_path=is_local_path)
|
||||
return urllib.parse.urlunparse(result._replace(path=path))
|
||||
return urllib.parse.urlunsplit(result._replace(path=path))
|
||||
|
||||
|
||||
def _absolute_link_url(base_url: str, url: str) -> str:
|
||||
"""
|
||||
A faster implementation of urllib.parse.urljoin with a shortcut
|
||||
for absolute http/https URLs.
|
||||
"""
|
||||
if url.startswith(("https://", "http://")):
|
||||
return url
|
||||
else:
|
||||
return urllib.parse.urljoin(base_url, url)
|
||||
|
||||
|
||||
@functools.total_ordering
|
||||
@ -185,6 +196,7 @@ class Link:
|
||||
__slots__ = [
|
||||
"_parsed_url",
|
||||
"_url",
|
||||
"_path",
|
||||
"_hashes",
|
||||
"comes_from",
|
||||
"requires_python",
|
||||
@ -241,6 +253,8 @@ class Link:
|
||||
# Store the url as a private attribute to prevent accidentally
|
||||
# trying to set a new value.
|
||||
self._url = url
|
||||
# The .path property is hot, so calculate its value ahead of time.
|
||||
self._path = urllib.parse.unquote(self._parsed_url.path)
|
||||
|
||||
link_hash = LinkHash.find_hash_url_fragment(url)
|
||||
hashes_from_link = {} if link_hash is None else link_hash.as_dict()
|
||||
@ -270,7 +284,7 @@ class Link:
|
||||
if file_url is None:
|
||||
return None
|
||||
|
||||
url = _ensure_quoted_url(urllib.parse.urljoin(page_url, file_url))
|
||||
url = _ensure_quoted_url(_absolute_link_url(page_url, file_url))
|
||||
pyrequire = file_data.get("requires-python")
|
||||
yanked_reason = file_data.get("yanked")
|
||||
hashes = file_data.get("hashes", {})
|
||||
@ -322,7 +336,7 @@ class Link:
|
||||
if not href:
|
||||
return None
|
||||
|
||||
url = _ensure_quoted_url(urllib.parse.urljoin(base_url, href))
|
||||
url = _ensure_quoted_url(_absolute_link_url(base_url, href))
|
||||
pyrequire = anchor_attribs.get("data-requires-python")
|
||||
yanked_reason = anchor_attribs.get("data-yanked")
|
||||
|
||||
@ -421,7 +435,7 @@ class Link:
|
||||
|
||||
@property
|
||||
def path(self) -> str:
|
||||
return urllib.parse.unquote(self._parsed_url.path)
|
||||
return self._path
|
||||
|
||||
def splitext(self) -> Tuple[str, str]:
|
||||
return splitext(posixpath.basename(self.path.rstrip("/")))
|
||||
@ -452,10 +466,10 @@ class Link:
|
||||
project_name = match.group(1)
|
||||
if not self._project_name_re.match(project_name):
|
||||
deprecated(
|
||||
reason=f"{self} contains an egg fragment with a non-PEP 508 name",
|
||||
reason=f"{self} contains an egg fragment with a non-PEP 508 name.",
|
||||
replacement="to use the req @ url syntax, and remove the egg fragment",
|
||||
gone_in="25.0",
|
||||
issue=11617,
|
||||
gone_in="25.1",
|
||||
issue=13157,
|
||||
)
|
||||
|
||||
return project_name
|
||||
|
||||
@ -76,6 +76,18 @@ class SafeFileCache(SeparateBodyBaseCache):
|
||||
|
||||
with adjacent_tmp_file(path) as f:
|
||||
f.write(data)
|
||||
# Inherit the read/write permissions of the cache directory
|
||||
# to enable multi-user cache use-cases.
|
||||
mode = (
|
||||
os.stat(self.directory).st_mode
|
||||
& 0o666 # select read/write permissions of cache directory
|
||||
| 0o600 # set owner read/write permissions
|
||||
)
|
||||
# Change permissions only if there is no risk of following a symlink.
|
||||
if os.chmod in os.supports_fd:
|
||||
os.chmod(f.fileno(), mode)
|
||||
elif os.chmod in os.supports_follow_symlinks:
|
||||
os.chmod(f.name, mode, follow_symlinks=False)
|
||||
|
||||
replace(f.name, path)
|
||||
|
||||
|
||||
@ -339,6 +339,7 @@ class PipSession(requests.Session):
|
||||
# Namespace the attribute with "pip_" just in case to prevent
|
||||
# possible conflicts with the base class.
|
||||
self.pip_trusted_origins: List[Tuple[str, Optional[int]]] = []
|
||||
self.pip_proxy = None
|
||||
|
||||
# Attach our User Agent to the request
|
||||
self.headers["User-Agent"] = user_agent()
|
||||
|
||||
@ -38,4 +38,5 @@ def generate_editable_metadata(
|
||||
except InstallationSubprocessError as error:
|
||||
raise MetadataGenerationFailed(package_details=details) from error
|
||||
|
||||
assert distinfo_dir is not None
|
||||
return os.path.join(metadata_dir, distinfo_dir)
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import collections
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Container, Dict, Generator, Iterable, List, NamedTuple, Optional, Set
|
||||
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
|
||||
from pip._vendor.packaging.version import InvalidVersion
|
||||
|
||||
from pip._internal.exceptions import BadCommand, InstallationError
|
||||
@ -220,19 +221,16 @@ def _get_editable_info(dist: BaseDistribution) -> _EditableInfo:
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FrozenRequirement:
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
req: str,
|
||||
editable: bool,
|
||||
comments: Iterable[str] = (),
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.canonical_name = canonicalize_name(name)
|
||||
self.req = req
|
||||
self.editable = editable
|
||||
self.comments = comments
|
||||
name: str
|
||||
req: str
|
||||
editable: bool
|
||||
comments: Iterable[str] = field(default_factory=tuple)
|
||||
|
||||
@property
|
||||
def canonical_name(self) -> NormalizedName:
|
||||
return canonicalize_name(self.name)
|
||||
|
||||
@classmethod
|
||||
def from_dist(cls, dist: BaseDistribution) -> "FrozenRequirement":
|
||||
|
||||
@ -73,7 +73,7 @@ def load_pyproject_toml(
|
||||
build_system = None
|
||||
|
||||
# The following cases must use PEP 517
|
||||
# We check for use_pep517 being non-None and falsey because that means
|
||||
# We check for use_pep517 being non-None and falsy because that means
|
||||
# the user explicitly requested --no-use-pep517. The value 0 as
|
||||
# opposed to False can occur when the value is provided via an
|
||||
# environment variable or config file option (due to the quirk of
|
||||
|
||||
@ -2,12 +2,16 @@
|
||||
Requirements file parsing
|
||||
"""
|
||||
|
||||
import codecs
|
||||
import locale
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
import urllib.parse
|
||||
from dataclasses import dataclass
|
||||
from optparse import Values
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
@ -25,7 +29,6 @@ from typing import (
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.exceptions import InstallationError, RequirementsFileParseError
|
||||
from pip._internal.models.search_scope import SearchScope
|
||||
from pip._internal.utils.encoding import auto_decode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
@ -81,52 +84,66 @@ SUPPORTED_OPTIONS_EDITABLE_REQ_DEST = [
|
||||
str(o().dest) for o in SUPPORTED_OPTIONS_EDITABLE_REQ
|
||||
]
|
||||
|
||||
# order of BOMS is important: codecs.BOM_UTF16_LE is a prefix of codecs.BOM_UTF32_LE
|
||||
# so data.startswith(BOM_UTF16_LE) would be true for UTF32_LE data
|
||||
BOMS: List[Tuple[bytes, str]] = [
|
||||
(codecs.BOM_UTF8, "utf-8"),
|
||||
(codecs.BOM_UTF32, "utf-32"),
|
||||
(codecs.BOM_UTF32_BE, "utf-32-be"),
|
||||
(codecs.BOM_UTF32_LE, "utf-32-le"),
|
||||
(codecs.BOM_UTF16, "utf-16"),
|
||||
(codecs.BOM_UTF16_BE, "utf-16-be"),
|
||||
(codecs.BOM_UTF16_LE, "utf-16-le"),
|
||||
]
|
||||
|
||||
PEP263_ENCODING_RE = re.compile(rb"coding[:=]\s*([-\w.]+)")
|
||||
DEFAULT_ENCODING = "utf-8"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParsedRequirement:
|
||||
def __init__(
|
||||
self,
|
||||
requirement: str,
|
||||
is_editable: bool,
|
||||
comes_from: str,
|
||||
constraint: bool,
|
||||
options: Optional[Dict[str, Any]] = None,
|
||||
line_source: Optional[str] = None,
|
||||
) -> None:
|
||||
self.requirement = requirement
|
||||
self.is_editable = is_editable
|
||||
self.comes_from = comes_from
|
||||
self.options = options
|
||||
self.constraint = constraint
|
||||
self.line_source = line_source
|
||||
# TODO: replace this with slots=True when dropping Python 3.9 support.
|
||||
__slots__ = (
|
||||
"requirement",
|
||||
"is_editable",
|
||||
"comes_from",
|
||||
"constraint",
|
||||
"options",
|
||||
"line_source",
|
||||
)
|
||||
|
||||
requirement: str
|
||||
is_editable: bool
|
||||
comes_from: str
|
||||
constraint: bool
|
||||
options: Optional[Dict[str, Any]]
|
||||
line_source: Optional[str]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParsedLine:
|
||||
def __init__(
|
||||
self,
|
||||
filename: str,
|
||||
lineno: int,
|
||||
args: str,
|
||||
opts: Values,
|
||||
constraint: bool,
|
||||
) -> None:
|
||||
self.filename = filename
|
||||
self.lineno = lineno
|
||||
self.opts = opts
|
||||
self.constraint = constraint
|
||||
__slots__ = ("filename", "lineno", "args", "opts", "constraint")
|
||||
|
||||
if args:
|
||||
self.is_requirement = True
|
||||
self.is_editable = False
|
||||
self.requirement = args
|
||||
elif opts.editables:
|
||||
self.is_requirement = True
|
||||
self.is_editable = True
|
||||
filename: str
|
||||
lineno: int
|
||||
args: str
|
||||
opts: Values
|
||||
constraint: bool
|
||||
|
||||
@property
|
||||
def is_editable(self) -> bool:
|
||||
return bool(self.opts.editables)
|
||||
|
||||
@property
|
||||
def requirement(self) -> Optional[str]:
|
||||
if self.args:
|
||||
return self.args
|
||||
elif self.is_editable:
|
||||
# We don't support multiple -e on one line
|
||||
self.requirement = opts.editables[0]
|
||||
else:
|
||||
self.is_requirement = False
|
||||
return self.opts.editables[0]
|
||||
return None
|
||||
|
||||
|
||||
def parse_requirements(
|
||||
@ -179,7 +196,7 @@ def handle_requirement_line(
|
||||
line.lineno,
|
||||
)
|
||||
|
||||
assert line.is_requirement
|
||||
assert line.requirement is not None
|
||||
|
||||
# get the options that apply to requirements
|
||||
if line.is_editable:
|
||||
@ -301,7 +318,7 @@ def handle_line(
|
||||
affect the finder.
|
||||
"""
|
||||
|
||||
if line.is_requirement:
|
||||
if line.requirement is not None:
|
||||
parsed_req = handle_requirement_line(line, options)
|
||||
return parsed_req
|
||||
else:
|
||||
@ -340,7 +357,7 @@ class RequirementsFileParser:
|
||||
parsed_files_stack: List[Dict[str, Optional[str]]],
|
||||
) -> Generator[ParsedLine, None, None]:
|
||||
for line in self._parse_file(filename, constraint):
|
||||
if not line.is_requirement and (
|
||||
if line.requirement is None and (
|
||||
line.opts.requirements or line.opts.constraints
|
||||
):
|
||||
# parse a nested requirements file
|
||||
@ -568,7 +585,39 @@ def get_file_content(url: str, session: "PipSession") -> Tuple[str, str]:
|
||||
# Assume this is a bare path.
|
||||
try:
|
||||
with open(url, "rb") as f:
|
||||
content = auto_decode(f.read())
|
||||
raw_content = f.read()
|
||||
except OSError as exc:
|
||||
raise InstallationError(f"Could not open requirements file: {exc}")
|
||||
|
||||
content = _decode_req_file(raw_content, url)
|
||||
|
||||
return url, content
|
||||
|
||||
|
||||
def _decode_req_file(data: bytes, url: str) -> str:
|
||||
for bom, encoding in BOMS:
|
||||
if data.startswith(bom):
|
||||
return data[len(bom) :].decode(encoding)
|
||||
|
||||
for line in data.split(b"\n")[:2]:
|
||||
if line[0:1] == b"#":
|
||||
result = PEP263_ENCODING_RE.search(line)
|
||||
if result is not None:
|
||||
encoding = result.groups()[0].decode("ascii")
|
||||
return data.decode(encoding)
|
||||
|
||||
try:
|
||||
return data.decode(DEFAULT_ENCODING)
|
||||
except UnicodeDecodeError:
|
||||
locale_encoding = locale.getpreferredencoding(False) or sys.getdefaultencoding()
|
||||
logging.warning(
|
||||
"unable to decode data from %s with default encoding %s, "
|
||||
"falling back to encoding from locale: %s. "
|
||||
"If this is intentional you should specify the encoding with a "
|
||||
"PEP-263 style comment, e.g. '# -*- coding: %s -*-'",
|
||||
url,
|
||||
DEFAULT_ENCODING,
|
||||
locale_encoding,
|
||||
locale_encoding,
|
||||
)
|
||||
return data.decode(locale_encoding)
|
||||
|
||||
@ -837,7 +837,7 @@ class InstallRequirement:
|
||||
"try using --config-settings editable_mode=compat. "
|
||||
"Please consult the setuptools documentation for more information"
|
||||
),
|
||||
gone_in="25.0",
|
||||
gone_in="25.1",
|
||||
issue=11457,
|
||||
)
|
||||
if self.config_settings:
|
||||
@ -925,7 +925,7 @@ def check_legacy_setup_py_options(
|
||||
reason="--build-option and --global-option are deprecated.",
|
||||
issue=11859,
|
||||
replacement="to use --config-settings",
|
||||
gone_in="25.0",
|
||||
gone_in=None,
|
||||
)
|
||||
logger.warning(
|
||||
"Implying --no-binary=:all: due to the presence of "
|
||||
|
||||
@ -309,7 +309,7 @@ class Factory:
|
||||
specifier=specifier,
|
||||
hashes=hashes,
|
||||
)
|
||||
icans = list(result.iter_applicable())
|
||||
icans = result.applicable_candidates
|
||||
|
||||
# PEP 592: Yanked releases are ignored unless the specifier
|
||||
# explicitly pins a version (via '==' or '===') that can be
|
||||
|
||||
@ -26,7 +26,11 @@ from pip._internal.utils.entrypoints import (
|
||||
get_best_invocation_for_this_python,
|
||||
)
|
||||
from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace
|
||||
from pip._internal.utils.misc import ensure_dir
|
||||
from pip._internal.utils.misc import (
|
||||
ExternallyManagedEnvironment,
|
||||
check_externally_managed,
|
||||
ensure_dir,
|
||||
)
|
||||
|
||||
_WEEK = datetime.timedelta(days=7)
|
||||
|
||||
@ -231,6 +235,10 @@ def pip_self_version_check(session: PipSession, options: optparse.Values) -> Non
|
||||
installed_dist = get_default_environment().get_distribution("pip")
|
||||
if not installed_dist:
|
||||
return
|
||||
try:
|
||||
check_externally_managed()
|
||||
except ExternallyManagedEnvironment:
|
||||
return
|
||||
|
||||
upgrade_prompt = _self_version_check_logic(
|
||||
state=SelfCheckState(cache_dir=options.cache_dir),
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
import codecs
|
||||
import locale
|
||||
import re
|
||||
import sys
|
||||
from typing import List, Tuple
|
||||
|
||||
BOMS: List[Tuple[bytes, str]] = [
|
||||
(codecs.BOM_UTF8, "utf-8"),
|
||||
(codecs.BOM_UTF16, "utf-16"),
|
||||
(codecs.BOM_UTF16_BE, "utf-16-be"),
|
||||
(codecs.BOM_UTF16_LE, "utf-16-le"),
|
||||
(codecs.BOM_UTF32, "utf-32"),
|
||||
(codecs.BOM_UTF32_BE, "utf-32-be"),
|
||||
(codecs.BOM_UTF32_LE, "utf-32-le"),
|
||||
]
|
||||
|
||||
ENCODING_RE = re.compile(rb"coding[:=]\s*([-\w.]+)")
|
||||
|
||||
|
||||
def auto_decode(data: bytes) -> str:
|
||||
"""Check a bytes string for a BOM to correctly detect the encoding
|
||||
|
||||
Fallback to locale.getpreferredencoding(False) like open() on Python3"""
|
||||
for bom, encoding in BOMS:
|
||||
if data.startswith(bom):
|
||||
return data[len(bom) :].decode(encoding)
|
||||
# Lets check the first two lines as in PEP263
|
||||
for line in data.split(b"\n")[:2]:
|
||||
if line[0:1] == b"#" and ENCODING_RE.search(line):
|
||||
result = ENCODING_RE.search(line)
|
||||
assert result is not None
|
||||
encoding = result.groups()[0].decode("ascii")
|
||||
return data.decode(encoding)
|
||||
return data.decode(
|
||||
locale.getpreferredencoding(False) or sys.getdefaultencoding(),
|
||||
)
|
||||
@ -137,12 +137,19 @@ class IndentedRenderable:
|
||||
yield Segment("\n")
|
||||
|
||||
|
||||
class PipConsole(Console):
|
||||
def on_broken_pipe(self) -> None:
|
||||
# Reraise the original exception, rich 13.8.0+ exits by default
|
||||
# instead, preventing our handler from firing.
|
||||
raise BrokenPipeError() from None
|
||||
|
||||
|
||||
class RichPipStreamHandler(RichHandler):
|
||||
KEYWORDS: ClassVar[Optional[List[str]]] = []
|
||||
|
||||
def __init__(self, stream: Optional[TextIO], no_color: bool) -> None:
|
||||
super().__init__(
|
||||
console=Console(file=stream, no_color=no_color, soft_wrap=True),
|
||||
console=PipConsole(file=stream, no_color=no_color, soft_wrap=True),
|
||||
show_time=False,
|
||||
show_level=False,
|
||||
show_path=False,
|
||||
|
||||
@ -19,12 +19,13 @@ from typing import (
|
||||
Any,
|
||||
BinaryIO,
|
||||
Callable,
|
||||
Dict,
|
||||
Generator,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Mapping,
|
||||
Optional,
|
||||
Sequence,
|
||||
TextIO,
|
||||
Tuple,
|
||||
Type,
|
||||
@ -667,7 +668,7 @@ class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
||||
def build_wheel(
|
||||
self,
|
||||
wheel_directory: str,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
metadata_directory: Optional[str] = None,
|
||||
) -> str:
|
||||
cs = self.config_holder.config_settings
|
||||
@ -678,7 +679,7 @@ class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
||||
def build_sdist(
|
||||
self,
|
||||
sdist_directory: str,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
) -> str:
|
||||
cs = self.config_holder.config_settings
|
||||
return super().build_sdist(sdist_directory, config_settings=cs)
|
||||
@ -686,7 +687,7 @@ class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
||||
def build_editable(
|
||||
self,
|
||||
wheel_directory: str,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
metadata_directory: Optional[str] = None,
|
||||
) -> str:
|
||||
cs = self.config_holder.config_settings
|
||||
@ -695,27 +696,27 @@ class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
||||
)
|
||||
|
||||
def get_requires_for_build_wheel(
|
||||
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
||||
) -> List[str]:
|
||||
self, config_settings: Optional[Mapping[str, Any]] = None
|
||||
) -> Sequence[str]:
|
||||
cs = self.config_holder.config_settings
|
||||
return super().get_requires_for_build_wheel(config_settings=cs)
|
||||
|
||||
def get_requires_for_build_sdist(
|
||||
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
||||
) -> List[str]:
|
||||
self, config_settings: Optional[Mapping[str, Any]] = None
|
||||
) -> Sequence[str]:
|
||||
cs = self.config_holder.config_settings
|
||||
return super().get_requires_for_build_sdist(config_settings=cs)
|
||||
|
||||
def get_requires_for_build_editable(
|
||||
self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
|
||||
) -> List[str]:
|
||||
self, config_settings: Optional[Mapping[str, Any]] = None
|
||||
) -> Sequence[str]:
|
||||
cs = self.config_holder.config_settings
|
||||
return super().get_requires_for_build_editable(config_settings=cs)
|
||||
|
||||
def prepare_metadata_for_build_wheel(
|
||||
self,
|
||||
metadata_directory: str,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
_allow_fallback: bool = True,
|
||||
) -> str:
|
||||
cs = self.config_holder.config_settings
|
||||
@ -728,9 +729,9 @@ class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
|
||||
def prepare_metadata_for_build_editable(
|
||||
self,
|
||||
metadata_directory: str,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
_allow_fallback: bool = True,
|
||||
) -> str:
|
||||
) -> Optional[str]:
|
||||
cs = self.config_holder.config_settings
|
||||
return super().prepare_metadata_for_build_editable(
|
||||
metadata_directory=metadata_directory,
|
||||
@ -764,7 +765,7 @@ def warn_if_run_as_root() -> None:
|
||||
logger.warning(
|
||||
"Running pip as the 'root' user can result in broken permissions and "
|
||||
"conflicting behaviour with the system package manager, possibly "
|
||||
"rendering your system unusable."
|
||||
"rendering your system unusable. "
|
||||
"It is recommended to use a virtual environment instead: "
|
||||
"https://pip.pypa.io/warnings/venv. "
|
||||
"Use the --root-user-action option if you know what you are doing and "
|
||||
|
||||
@ -11,6 +11,7 @@ NormalizedExtra = NewType("NormalizedExtra", str)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=32)
|
||||
def check_requires_python(
|
||||
requires_python: Optional[str], version_info: Tuple[int, ...]
|
||||
) -> bool:
|
||||
|
||||
@ -176,7 +176,7 @@ def untar_file(filename: str, location: str) -> None:
|
||||
)
|
||||
mode = "r:*"
|
||||
|
||||
tar = tarfile.open(filename, mode, encoding="utf-8")
|
||||
tar = tarfile.open(filename, mode, encoding="utf-8") # type: ignore
|
||||
try:
|
||||
leading = has_leading_dir([member.name for member in tar.getmembers()])
|
||||
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
|
||||
Make it easy to import from cachecontrol without long namespaces.
|
||||
"""
|
||||
|
||||
__author__ = "Eric Larson"
|
||||
__email__ = "eric@ionrock.org"
|
||||
__version__ = "0.14.0"
|
||||
__version__ = "0.14.1"
|
||||
|
||||
from pip._vendor.cachecontrol.adapter import CacheControlAdapter
|
||||
from pip._vendor.cachecontrol.controller import CacheController
|
||||
|
||||
@ -77,7 +77,7 @@ class CacheControlAdapter(HTTPAdapter):
|
||||
|
||||
return resp
|
||||
|
||||
def build_response(
|
||||
def build_response( # type: ignore[override]
|
||||
self,
|
||||
request: PreparedRequest,
|
||||
response: HTTPResponse,
|
||||
@ -143,7 +143,7 @@ class CacheControlAdapter(HTTPAdapter):
|
||||
_update_chunk_length, response
|
||||
)
|
||||
|
||||
resp: Response = super().build_response(request, response) # type: ignore[no-untyped-call]
|
||||
resp: Response = super().build_response(request, response)
|
||||
|
||||
# See if we should invalidate the cache.
|
||||
if request.method in self.invalidating_methods and resp.ok:
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
The cache object API for implementing caches. The default is a thread
|
||||
safe in-memory dictionary.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from threading import Lock
|
||||
|
||||
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import os
|
||||
from textwrap import dedent
|
||||
from typing import IO, TYPE_CHECKING, Union
|
||||
from typing import IO, TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from pip._vendor.cachecontrol.cache import BaseCache, SeparateBodyBaseCache
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"""
|
||||
The httplib2 algorithms ported for use with requests.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import calendar
|
||||
|
||||
@ -38,10 +38,10 @@ class CallbackFileWrapper:
|
||||
self.__callback = callback
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
# The vaguaries of garbage collection means that self.__fp is
|
||||
# The vagaries of garbage collection means that self.__fp is
|
||||
# not always set. By using __getattribute__ and the private
|
||||
# name[0] allows looking up the attribute value and raising an
|
||||
# AttributeError when it doesn't exist. This stop thigns from
|
||||
# AttributeError when it doesn't exist. This stop things from
|
||||
# infinitely recursing calls to getattr in the case where
|
||||
# self.__fp hasn't been set.
|
||||
#
|
||||
|
||||
@ -68,7 +68,10 @@ class OneDayCache(BaseHeuristic):
|
||||
|
||||
if "expires" not in response.headers:
|
||||
date = parsedate(response.headers["date"])
|
||||
expires = expire_after(timedelta(days=1), date=datetime(*date[:6], tzinfo=timezone.utc)) # type: ignore[index,misc]
|
||||
expires = expire_after(
|
||||
timedelta(days=1),
|
||||
date=datetime(*date[:6], tzinfo=timezone.utc), # type: ignore[index,misc]
|
||||
)
|
||||
headers["expires"] = datetime_to_header(expires)
|
||||
headers["cache-control"] = "public"
|
||||
return headers
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
from .package_data import __version__
|
||||
from .core import (
|
||||
IDNABidiError,
|
||||
IDNAError,
|
||||
@ -20,8 +19,10 @@ from .core import (
|
||||
valid_string_length,
|
||||
)
|
||||
from .intranges import intranges_contain
|
||||
from .package_data import __version__
|
||||
|
||||
__all__ = [
|
||||
"__version__",
|
||||
"IDNABidiError",
|
||||
"IDNAError",
|
||||
"InvalidCodepoint",
|
||||
|
||||
@ -1,49 +1,51 @@
|
||||
from .core import encode, decode, alabel, ulabel, IDNAError
|
||||
import codecs
|
||||
import re
|
||||
from typing import Any, Tuple, Optional
|
||||
from typing import Any, Optional, Tuple
|
||||
|
||||
from .core import IDNAError, alabel, decode, encode, ulabel
|
||||
|
||||
_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]")
|
||||
|
||||
_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
|
||||
|
||||
class Codec(codecs.Codec):
|
||||
|
||||
def encode(self, data: str, errors: str = 'strict') -> Tuple[bytes, int]:
|
||||
if errors != 'strict':
|
||||
raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
|
||||
def encode(self, data: str, errors: str = "strict") -> Tuple[bytes, int]:
|
||||
if errors != "strict":
|
||||
raise IDNAError('Unsupported error handling "{}"'.format(errors))
|
||||
|
||||
if not data:
|
||||
return b"", 0
|
||||
|
||||
return encode(data), len(data)
|
||||
|
||||
def decode(self, data: bytes, errors: str = 'strict') -> Tuple[str, int]:
|
||||
if errors != 'strict':
|
||||
raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
|
||||
def decode(self, data: bytes, errors: str = "strict") -> Tuple[str, int]:
|
||||
if errors != "strict":
|
||||
raise IDNAError('Unsupported error handling "{}"'.format(errors))
|
||||
|
||||
if not data:
|
||||
return '', 0
|
||||
return "", 0
|
||||
|
||||
return decode(data), len(data)
|
||||
|
||||
|
||||
class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
|
||||
def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]:
|
||||
if errors != 'strict':
|
||||
raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
|
||||
if errors != "strict":
|
||||
raise IDNAError('Unsupported error handling "{}"'.format(errors))
|
||||
|
||||
if not data:
|
||||
return b'', 0
|
||||
return b"", 0
|
||||
|
||||
labels = _unicode_dots_re.split(data)
|
||||
trailing_dot = b''
|
||||
trailing_dot = b""
|
||||
if labels:
|
||||
if not labels[-1]:
|
||||
trailing_dot = b'.'
|
||||
trailing_dot = b"."
|
||||
del labels[-1]
|
||||
elif not final:
|
||||
# Keep potentially unfinished label until the next call
|
||||
del labels[-1]
|
||||
if labels:
|
||||
trailing_dot = b'.'
|
||||
trailing_dot = b"."
|
||||
|
||||
result = []
|
||||
size = 0
|
||||
@ -54,32 +56,33 @@ class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
|
||||
size += len(label)
|
||||
|
||||
# Join with U+002E
|
||||
result_bytes = b'.'.join(result) + trailing_dot
|
||||
result_bytes = b".".join(result) + trailing_dot
|
||||
size += len(trailing_dot)
|
||||
return result_bytes, size
|
||||
|
||||
|
||||
class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
|
||||
def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]:
|
||||
if errors != 'strict':
|
||||
raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
|
||||
if errors != "strict":
|
||||
raise IDNAError('Unsupported error handling "{}"'.format(errors))
|
||||
|
||||
if not data:
|
||||
return ('', 0)
|
||||
return ("", 0)
|
||||
|
||||
if not isinstance(data, str):
|
||||
data = str(data, 'ascii')
|
||||
data = str(data, "ascii")
|
||||
|
||||
labels = _unicode_dots_re.split(data)
|
||||
trailing_dot = ''
|
||||
trailing_dot = ""
|
||||
if labels:
|
||||
if not labels[-1]:
|
||||
trailing_dot = '.'
|
||||
trailing_dot = "."
|
||||
del labels[-1]
|
||||
elif not final:
|
||||
# Keep potentially unfinished label until the next call
|
||||
del labels[-1]
|
||||
if labels:
|
||||
trailing_dot = '.'
|
||||
trailing_dot = "."
|
||||
|
||||
result = []
|
||||
size = 0
|
||||
@ -89,7 +92,7 @@ class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
|
||||
size += 1
|
||||
size += len(label)
|
||||
|
||||
result_str = '.'.join(result) + trailing_dot
|
||||
result_str = ".".join(result) + trailing_dot
|
||||
size += len(trailing_dot)
|
||||
return (result_str, size)
|
||||
|
||||
@ -103,7 +106,7 @@ class StreamReader(Codec, codecs.StreamReader):
|
||||
|
||||
|
||||
def search_function(name: str) -> Optional[codecs.CodecInfo]:
|
||||
if name != 'idna2008':
|
||||
if name != "idna2008":
|
||||
return None
|
||||
return codecs.CodecInfo(
|
||||
name=name,
|
||||
@ -115,4 +118,5 @@ def search_function(name: str) -> Optional[codecs.CodecInfo]:
|
||||
streamreader=StreamReader,
|
||||
)
|
||||
|
||||
|
||||
codecs.register(search_function)
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
from .core import *
|
||||
from .codec import *
|
||||
from typing import Any, Union
|
||||
|
||||
from .core import decode, encode
|
||||
|
||||
|
||||
def ToASCII(label: str) -> bytes:
|
||||
return encode(label)
|
||||
|
||||
|
||||
def ToUnicode(label: Union[bytes, bytearray]) -> str:
|
||||
return decode(label)
|
||||
|
||||
def nameprep(s: Any) -> None:
|
||||
raise NotImplementedError('IDNA 2008 does not utilise nameprep protocol')
|
||||
|
||||
def nameprep(s: Any) -> None:
|
||||
raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol")
|
||||
|
||||
@ -1,31 +1,37 @@
|
||||
from . import idnadata
|
||||
import bisect
|
||||
import unicodedata
|
||||
import re
|
||||
from typing import Union, Optional
|
||||
import unicodedata
|
||||
from typing import Optional, Union
|
||||
|
||||
from . import idnadata
|
||||
from .intranges import intranges_contain
|
||||
|
||||
_virama_combining_class = 9
|
||||
_alabel_prefix = b'xn--'
|
||||
_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
|
||||
_alabel_prefix = b"xn--"
|
||||
_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]")
|
||||
|
||||
|
||||
class IDNAError(UnicodeError):
|
||||
""" Base exception for all IDNA-encoding related problems """
|
||||
"""Base exception for all IDNA-encoding related problems"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class IDNABidiError(IDNAError):
|
||||
""" Exception when bidirectional requirements are not satisfied """
|
||||
"""Exception when bidirectional requirements are not satisfied"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class InvalidCodepoint(IDNAError):
|
||||
""" Exception when a disallowed or unallocated codepoint is used """
|
||||
"""Exception when a disallowed or unallocated codepoint is used"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class InvalidCodepointContext(IDNAError):
|
||||
""" Exception when the codepoint is not valid in the context it is used """
|
||||
"""Exception when the codepoint is not valid in the context it is used"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@ -33,17 +39,20 @@ def _combining_class(cp: int) -> int:
|
||||
v = unicodedata.combining(chr(cp))
|
||||
if v == 0:
|
||||
if not unicodedata.name(chr(cp)):
|
||||
raise ValueError('Unknown character in unicodedata')
|
||||
raise ValueError("Unknown character in unicodedata")
|
||||
return v
|
||||
|
||||
|
||||
def _is_script(cp: str, script: str) -> bool:
|
||||
return intranges_contain(ord(cp), idnadata.scripts[script])
|
||||
|
||||
|
||||
def _punycode(s: str) -> bytes:
|
||||
return s.encode('punycode')
|
||||
return s.encode("punycode")
|
||||
|
||||
|
||||
def _unot(s: int) -> str:
|
||||
return 'U+{:04X}'.format(s)
|
||||
return "U+{:04X}".format(s)
|
||||
|
||||
|
||||
def valid_label_length(label: Union[bytes, str]) -> bool:
|
||||
@ -61,96 +70,106 @@ def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool:
|
||||
def check_bidi(label: str, check_ltr: bool = False) -> bool:
|
||||
# Bidi rules should only be applied if string contains RTL characters
|
||||
bidi_label = False
|
||||
for (idx, cp) in enumerate(label, 1):
|
||||
for idx, cp in enumerate(label, 1):
|
||||
direction = unicodedata.bidirectional(cp)
|
||||
if direction == '':
|
||||
if direction == "":
|
||||
# String likely comes from a newer version of Unicode
|
||||
raise IDNABidiError('Unknown directionality in label {} at position {}'.format(repr(label), idx))
|
||||
if direction in ['R', 'AL', 'AN']:
|
||||
raise IDNABidiError("Unknown directionality in label {} at position {}".format(repr(label), idx))
|
||||
if direction in ["R", "AL", "AN"]:
|
||||
bidi_label = True
|
||||
if not bidi_label and not check_ltr:
|
||||
return True
|
||||
|
||||
# Bidi rule 1
|
||||
direction = unicodedata.bidirectional(label[0])
|
||||
if direction in ['R', 'AL']:
|
||||
if direction in ["R", "AL"]:
|
||||
rtl = True
|
||||
elif direction == 'L':
|
||||
elif direction == "L":
|
||||
rtl = False
|
||||
else:
|
||||
raise IDNABidiError('First codepoint in label {} must be directionality L, R or AL'.format(repr(label)))
|
||||
raise IDNABidiError("First codepoint in label {} must be directionality L, R or AL".format(repr(label)))
|
||||
|
||||
valid_ending = False
|
||||
number_type = None # type: Optional[str]
|
||||
for (idx, cp) in enumerate(label, 1):
|
||||
number_type: Optional[str] = None
|
||||
for idx, cp in enumerate(label, 1):
|
||||
direction = unicodedata.bidirectional(cp)
|
||||
|
||||
if rtl:
|
||||
# Bidi rule 2
|
||||
if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
|
||||
raise IDNABidiError('Invalid direction for codepoint at position {} in a right-to-left label'.format(idx))
|
||||
if direction not in [
|
||||
"R",
|
||||
"AL",
|
||||
"AN",
|
||||
"EN",
|
||||
"ES",
|
||||
"CS",
|
||||
"ET",
|
||||
"ON",
|
||||
"BN",
|
||||
"NSM",
|
||||
]:
|
||||
raise IDNABidiError("Invalid direction for codepoint at position {} in a right-to-left label".format(idx))
|
||||
# Bidi rule 3
|
||||
if direction in ['R', 'AL', 'EN', 'AN']:
|
||||
if direction in ["R", "AL", "EN", "AN"]:
|
||||
valid_ending = True
|
||||
elif direction != 'NSM':
|
||||
elif direction != "NSM":
|
||||
valid_ending = False
|
||||
# Bidi rule 4
|
||||
if direction in ['AN', 'EN']:
|
||||
if direction in ["AN", "EN"]:
|
||||
if not number_type:
|
||||
number_type = direction
|
||||
else:
|
||||
if number_type != direction:
|
||||
raise IDNABidiError('Can not mix numeral types in a right-to-left label')
|
||||
raise IDNABidiError("Can not mix numeral types in a right-to-left label")
|
||||
else:
|
||||
# Bidi rule 5
|
||||
if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
|
||||
raise IDNABidiError('Invalid direction for codepoint at position {} in a left-to-right label'.format(idx))
|
||||
if direction not in ["L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"]:
|
||||
raise IDNABidiError("Invalid direction for codepoint at position {} in a left-to-right label".format(idx))
|
||||
# Bidi rule 6
|
||||
if direction in ['L', 'EN']:
|
||||
if direction in ["L", "EN"]:
|
||||
valid_ending = True
|
||||
elif direction != 'NSM':
|
||||
elif direction != "NSM":
|
||||
valid_ending = False
|
||||
|
||||
if not valid_ending:
|
||||
raise IDNABidiError('Label ends with illegal codepoint directionality')
|
||||
raise IDNABidiError("Label ends with illegal codepoint directionality")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_initial_combiner(label: str) -> bool:
|
||||
if unicodedata.category(label[0])[0] == 'M':
|
||||
raise IDNAError('Label begins with an illegal combining character')
|
||||
if unicodedata.category(label[0])[0] == "M":
|
||||
raise IDNAError("Label begins with an illegal combining character")
|
||||
return True
|
||||
|
||||
|
||||
def check_hyphen_ok(label: str) -> bool:
|
||||
if label[2:4] == '--':
|
||||
raise IDNAError('Label has disallowed hyphens in 3rd and 4th position')
|
||||
if label[0] == '-' or label[-1] == '-':
|
||||
raise IDNAError('Label must not start or end with a hyphen')
|
||||
if label[2:4] == "--":
|
||||
raise IDNAError("Label has disallowed hyphens in 3rd and 4th position")
|
||||
if label[0] == "-" or label[-1] == "-":
|
||||
raise IDNAError("Label must not start or end with a hyphen")
|
||||
return True
|
||||
|
||||
|
||||
def check_nfc(label: str) -> None:
|
||||
if unicodedata.normalize('NFC', label) != label:
|
||||
raise IDNAError('Label must be in Normalization Form C')
|
||||
if unicodedata.normalize("NFC", label) != label:
|
||||
raise IDNAError("Label must be in Normalization Form C")
|
||||
|
||||
|
||||
def valid_contextj(label: str, pos: int) -> bool:
|
||||
cp_value = ord(label[pos])
|
||||
|
||||
if cp_value == 0x200c:
|
||||
|
||||
if cp_value == 0x200C:
|
||||
if pos > 0:
|
||||
if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
|
||||
return True
|
||||
|
||||
ok = False
|
||||
for i in range(pos-1, -1, -1):
|
||||
for i in range(pos - 1, -1, -1):
|
||||
joining_type = idnadata.joining_types.get(ord(label[i]))
|
||||
if joining_type == ord('T'):
|
||||
if joining_type == ord("T"):
|
||||
continue
|
||||
elif joining_type in [ord('L'), ord('D')]:
|
||||
elif joining_type in [ord("L"), ord("D")]:
|
||||
ok = True
|
||||
break
|
||||
else:
|
||||
@ -160,63 +179,61 @@ def valid_contextj(label: str, pos: int) -> bool:
|
||||
return False
|
||||
|
||||
ok = False
|
||||
for i in range(pos+1, len(label)):
|
||||
for i in range(pos + 1, len(label)):
|
||||
joining_type = idnadata.joining_types.get(ord(label[i]))
|
||||
if joining_type == ord('T'):
|
||||
if joining_type == ord("T"):
|
||||
continue
|
||||
elif joining_type in [ord('R'), ord('D')]:
|
||||
elif joining_type in [ord("R"), ord("D")]:
|
||||
ok = True
|
||||
break
|
||||
else:
|
||||
break
|
||||
return ok
|
||||
|
||||
if cp_value == 0x200d:
|
||||
|
||||
if cp_value == 0x200D:
|
||||
if pos > 0:
|
||||
if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
|
||||
return True
|
||||
return False
|
||||
|
||||
else:
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def valid_contexto(label: str, pos: int, exception: bool = False) -> bool:
|
||||
cp_value = ord(label[pos])
|
||||
|
||||
if cp_value == 0x00b7:
|
||||
if 0 < pos < len(label)-1:
|
||||
if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c:
|
||||
if cp_value == 0x00B7:
|
||||
if 0 < pos < len(label) - 1:
|
||||
if ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C:
|
||||
return True
|
||||
return False
|
||||
|
||||
elif cp_value == 0x0375:
|
||||
if pos < len(label)-1 and len(label) > 1:
|
||||
return _is_script(label[pos + 1], 'Greek')
|
||||
if pos < len(label) - 1 and len(label) > 1:
|
||||
return _is_script(label[pos + 1], "Greek")
|
||||
return False
|
||||
|
||||
elif cp_value == 0x05f3 or cp_value == 0x05f4:
|
||||
elif cp_value == 0x05F3 or cp_value == 0x05F4:
|
||||
if pos > 0:
|
||||
return _is_script(label[pos - 1], 'Hebrew')
|
||||
return _is_script(label[pos - 1], "Hebrew")
|
||||
return False
|
||||
|
||||
elif cp_value == 0x30fb:
|
||||
elif cp_value == 0x30FB:
|
||||
for cp in label:
|
||||
if cp == '\u30fb':
|
||||
if cp == "\u30fb":
|
||||
continue
|
||||
if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'):
|
||||
if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"):
|
||||
return True
|
||||
return False
|
||||
|
||||
elif 0x660 <= cp_value <= 0x669:
|
||||
for cp in label:
|
||||
if 0x6f0 <= ord(cp) <= 0x06f9:
|
||||
if 0x6F0 <= ord(cp) <= 0x06F9:
|
||||
return False
|
||||
return True
|
||||
|
||||
elif 0x6f0 <= cp_value <= 0x6f9:
|
||||
elif 0x6F0 <= cp_value <= 0x6F9:
|
||||
for cp in label:
|
||||
if 0x660 <= ord(cp) <= 0x0669:
|
||||
return False
|
||||
@ -227,37 +244,49 @@ def valid_contexto(label: str, pos: int, exception: bool = False) -> bool:
|
||||
|
||||
def check_label(label: Union[str, bytes, bytearray]) -> None:
|
||||
if isinstance(label, (bytes, bytearray)):
|
||||
label = label.decode('utf-8')
|
||||
label = label.decode("utf-8")
|
||||
if len(label) == 0:
|
||||
raise IDNAError('Empty Label')
|
||||
raise IDNAError("Empty Label")
|
||||
|
||||
check_nfc(label)
|
||||
check_hyphen_ok(label)
|
||||
check_initial_combiner(label)
|
||||
|
||||
for (pos, cp) in enumerate(label):
|
||||
for pos, cp in enumerate(label):
|
||||
cp_value = ord(cp)
|
||||
if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']):
|
||||
if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]):
|
||||
continue
|
||||
elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']):
|
||||
if not valid_contextj(label, pos):
|
||||
raise InvalidCodepointContext('Joiner {} not allowed at position {} in {}'.format(
|
||||
_unot(cp_value), pos+1, repr(label)))
|
||||
elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']):
|
||||
elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]):
|
||||
try:
|
||||
if not valid_contextj(label, pos):
|
||||
raise InvalidCodepointContext(
|
||||
"Joiner {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label))
|
||||
)
|
||||
except ValueError:
|
||||
raise IDNAError(
|
||||
"Unknown codepoint adjacent to joiner {} at position {} in {}".format(
|
||||
_unot(cp_value), pos + 1, repr(label)
|
||||
)
|
||||
)
|
||||
elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]):
|
||||
if not valid_contexto(label, pos):
|
||||
raise InvalidCodepointContext('Codepoint {} not allowed at position {} in {}'.format(_unot(cp_value), pos+1, repr(label)))
|
||||
raise InvalidCodepointContext(
|
||||
"Codepoint {} not allowed at position {} in {}".format(_unot(cp_value), pos + 1, repr(label))
|
||||
)
|
||||
else:
|
||||
raise InvalidCodepoint('Codepoint {} at position {} of {} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
|
||||
raise InvalidCodepoint(
|
||||
"Codepoint {} at position {} of {} not allowed".format(_unot(cp_value), pos + 1, repr(label))
|
||||
)
|
||||
|
||||
check_bidi(label)
|
||||
|
||||
|
||||
def alabel(label: str) -> bytes:
|
||||
try:
|
||||
label_bytes = label.encode('ascii')
|
||||
label_bytes = label.encode("ascii")
|
||||
ulabel(label_bytes)
|
||||
if not valid_label_length(label_bytes):
|
||||
raise IDNAError('Label too long')
|
||||
raise IDNAError("Label too long")
|
||||
return label_bytes
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
@ -266,7 +295,7 @@ def alabel(label: str) -> bytes:
|
||||
label_bytes = _alabel_prefix + _punycode(label)
|
||||
|
||||
if not valid_label_length(label_bytes):
|
||||
raise IDNAError('Label too long')
|
||||
raise IDNAError("Label too long")
|
||||
|
||||
return label_bytes
|
||||
|
||||
@ -274,7 +303,7 @@ def alabel(label: str) -> bytes:
|
||||
def ulabel(label: Union[str, bytes, bytearray]) -> str:
|
||||
if not isinstance(label, (bytes, bytearray)):
|
||||
try:
|
||||
label_bytes = label.encode('ascii')
|
||||
label_bytes = label.encode("ascii")
|
||||
except UnicodeEncodeError:
|
||||
check_label(label)
|
||||
return label
|
||||
@ -283,19 +312,19 @@ def ulabel(label: Union[str, bytes, bytearray]) -> str:
|
||||
|
||||
label_bytes = label_bytes.lower()
|
||||
if label_bytes.startswith(_alabel_prefix):
|
||||
label_bytes = label_bytes[len(_alabel_prefix):]
|
||||
label_bytes = label_bytes[len(_alabel_prefix) :]
|
||||
if not label_bytes:
|
||||
raise IDNAError('Malformed A-label, no Punycode eligible content found')
|
||||
if label_bytes.decode('ascii')[-1] == '-':
|
||||
raise IDNAError('A-label must not end with a hyphen')
|
||||
raise IDNAError("Malformed A-label, no Punycode eligible content found")
|
||||
if label_bytes.decode("ascii")[-1] == "-":
|
||||
raise IDNAError("A-label must not end with a hyphen")
|
||||
else:
|
||||
check_label(label_bytes)
|
||||
return label_bytes.decode('ascii')
|
||||
return label_bytes.decode("ascii")
|
||||
|
||||
try:
|
||||
label = label_bytes.decode('punycode')
|
||||
label = label_bytes.decode("punycode")
|
||||
except UnicodeError:
|
||||
raise IDNAError('Invalid A-label')
|
||||
raise IDNAError("Invalid A-label")
|
||||
check_label(label)
|
||||
return label
|
||||
|
||||
@ -303,52 +332,60 @@ def ulabel(label: Union[str, bytes, bytearray]) -> str:
|
||||
def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str:
|
||||
"""Re-map the characters in the string according to UTS46 processing."""
|
||||
from .uts46data import uts46data
|
||||
output = ''
|
||||
|
||||
output = ""
|
||||
|
||||
for pos, char in enumerate(domain):
|
||||
code_point = ord(char)
|
||||
try:
|
||||
uts46row = uts46data[code_point if code_point < 256 else
|
||||
bisect.bisect_left(uts46data, (code_point, 'Z')) - 1]
|
||||
uts46row = uts46data[code_point if code_point < 256 else bisect.bisect_left(uts46data, (code_point, "Z")) - 1]
|
||||
status = uts46row[1]
|
||||
replacement = None # type: Optional[str]
|
||||
replacement: Optional[str] = None
|
||||
if len(uts46row) == 3:
|
||||
replacement = uts46row[2]
|
||||
if (status == 'V' or
|
||||
(status == 'D' and not transitional) or
|
||||
(status == '3' and not std3_rules and replacement is None)):
|
||||
if (
|
||||
status == "V"
|
||||
or (status == "D" and not transitional)
|
||||
or (status == "3" and not std3_rules and replacement is None)
|
||||
):
|
||||
output += char
|
||||
elif replacement is not None and (status == 'M' or
|
||||
(status == '3' and not std3_rules) or
|
||||
(status == 'D' and transitional)):
|
||||
elif replacement is not None and (
|
||||
status == "M" or (status == "3" and not std3_rules) or (status == "D" and transitional)
|
||||
):
|
||||
output += replacement
|
||||
elif status != 'I':
|
||||
elif status != "I":
|
||||
raise IndexError()
|
||||
except IndexError:
|
||||
raise InvalidCodepoint(
|
||||
'Codepoint {} not allowed at position {} in {}'.format(
|
||||
_unot(code_point), pos + 1, repr(domain)))
|
||||
"Codepoint {} not allowed at position {} in {}".format(_unot(code_point), pos + 1, repr(domain))
|
||||
)
|
||||
|
||||
return unicodedata.normalize('NFC', output)
|
||||
return unicodedata.normalize("NFC", output)
|
||||
|
||||
|
||||
def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False, transitional: bool = False) -> bytes:
|
||||
def encode(
|
||||
s: Union[str, bytes, bytearray],
|
||||
strict: bool = False,
|
||||
uts46: bool = False,
|
||||
std3_rules: bool = False,
|
||||
transitional: bool = False,
|
||||
) -> bytes:
|
||||
if not isinstance(s, str):
|
||||
try:
|
||||
s = str(s, 'ascii')
|
||||
s = str(s, "ascii")
|
||||
except UnicodeDecodeError:
|
||||
raise IDNAError('should pass a unicode string to the function rather than a byte string.')
|
||||
raise IDNAError("should pass a unicode string to the function rather than a byte string.")
|
||||
if uts46:
|
||||
s = uts46_remap(s, std3_rules, transitional)
|
||||
trailing_dot = False
|
||||
result = []
|
||||
if strict:
|
||||
labels = s.split('.')
|
||||
labels = s.split(".")
|
||||
else:
|
||||
labels = _unicode_dots_re.split(s)
|
||||
if not labels or labels == ['']:
|
||||
raise IDNAError('Empty domain')
|
||||
if labels[-1] == '':
|
||||
if not labels or labels == [""]:
|
||||
raise IDNAError("Empty domain")
|
||||
if labels[-1] == "":
|
||||
del labels[-1]
|
||||
trailing_dot = True
|
||||
for label in labels:
|
||||
@ -356,21 +393,26 @@ def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
|
||||
if s:
|
||||
result.append(s)
|
||||
else:
|
||||
raise IDNAError('Empty label')
|
||||
raise IDNAError("Empty label")
|
||||
if trailing_dot:
|
||||
result.append(b'')
|
||||
s = b'.'.join(result)
|
||||
result.append(b"")
|
||||
s = b".".join(result)
|
||||
if not valid_string_length(s, trailing_dot):
|
||||
raise IDNAError('Domain too long')
|
||||
raise IDNAError("Domain too long")
|
||||
return s
|
||||
|
||||
|
||||
def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False) -> str:
|
||||
def decode(
|
||||
s: Union[str, bytes, bytearray],
|
||||
strict: bool = False,
|
||||
uts46: bool = False,
|
||||
std3_rules: bool = False,
|
||||
) -> str:
|
||||
try:
|
||||
if not isinstance(s, str):
|
||||
s = str(s, 'ascii')
|
||||
s = str(s, "ascii")
|
||||
except UnicodeDecodeError:
|
||||
raise IDNAError('Invalid ASCII in A-label')
|
||||
raise IDNAError("Invalid ASCII in A-label")
|
||||
if uts46:
|
||||
s = uts46_remap(s, std3_rules, False)
|
||||
trailing_dot = False
|
||||
@ -378,9 +420,9 @@ def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
|
||||
if not strict:
|
||||
labels = _unicode_dots_re.split(s)
|
||||
else:
|
||||
labels = s.split('.')
|
||||
if not labels or labels == ['']:
|
||||
raise IDNAError('Empty domain')
|
||||
labels = s.split(".")
|
||||
if not labels or labels == [""]:
|
||||
raise IDNAError("Empty domain")
|
||||
if not labels[-1]:
|
||||
del labels[-1]
|
||||
trailing_dot = True
|
||||
@ -389,7 +431,7 @@ def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
|
||||
if s:
|
||||
result.append(s)
|
||||
else:
|
||||
raise IDNAError('Empty label')
|
||||
raise IDNAError("Empty label")
|
||||
if trailing_dot:
|
||||
result.append('')
|
||||
return '.'.join(result)
|
||||
result.append("")
|
||||
return ".".join(result)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ in the original list?" in time O(log(# runs)).
|
||||
import bisect
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
def intranges_from_list(list_: List[int]) -> Tuple[int, ...]:
|
||||
"""Represent a list of integers as a sequence of ranges:
|
||||
((start_0, end_0), (start_1, end_1), ...), such that the original
|
||||
@ -20,18 +21,20 @@ def intranges_from_list(list_: List[int]) -> Tuple[int, ...]:
|
||||
ranges = []
|
||||
last_write = -1
|
||||
for i in range(len(sorted_list)):
|
||||
if i+1 < len(sorted_list):
|
||||
if sorted_list[i] == sorted_list[i+1]-1:
|
||||
if i + 1 < len(sorted_list):
|
||||
if sorted_list[i] == sorted_list[i + 1] - 1:
|
||||
continue
|
||||
current_range = sorted_list[last_write+1:i+1]
|
||||
current_range = sorted_list[last_write + 1 : i + 1]
|
||||
ranges.append(_encode_range(current_range[0], current_range[-1] + 1))
|
||||
last_write = i
|
||||
|
||||
return tuple(ranges)
|
||||
|
||||
|
||||
def _encode_range(start: int, end: int) -> int:
|
||||
return (start << 32) | end
|
||||
|
||||
|
||||
def _decode_range(r: int) -> Tuple[int, int]:
|
||||
return (r >> 32), (r & ((1 << 32) - 1))
|
||||
|
||||
@ -43,7 +46,7 @@ def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool:
|
||||
# we could be immediately ahead of a tuple (start, end)
|
||||
# with start < int_ <= end
|
||||
if pos > 0:
|
||||
left, right = _decode_range(ranges[pos-1])
|
||||
left, right = _decode_range(ranges[pos - 1])
|
||||
if left <= int_ < right:
|
||||
return True
|
||||
# or we could be immediately behind a tuple (int_, end)
|
||||
|
||||
@ -1,2 +1 @@
|
||||
__version__ = '3.7'
|
||||
|
||||
__version__ = "3.10"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,20 @@
|
||||
from .exceptions import *
|
||||
from .ext import ExtType, Timestamp
|
||||
|
||||
# ruff: noqa: F401
|
||||
import os
|
||||
|
||||
from .exceptions import * # noqa: F403
|
||||
from .ext import ExtType, Timestamp
|
||||
|
||||
version = (1, 0, 8)
|
||||
__version__ = "1.0.8"
|
||||
version = (1, 1, 0)
|
||||
__version__ = "1.1.0"
|
||||
|
||||
|
||||
if os.environ.get("MSGPACK_PUREPYTHON"):
|
||||
from .fallback import Packer, unpackb, Unpacker
|
||||
from .fallback import Packer, Unpacker, unpackb
|
||||
else:
|
||||
try:
|
||||
from ._cmsgpack import Packer, unpackb, Unpacker
|
||||
from ._cmsgpack import Packer, Unpacker, unpackb
|
||||
except ImportError:
|
||||
from .fallback import Packer, unpackb, Unpacker
|
||||
from .fallback import Packer, Unpacker, unpackb
|
||||
|
||||
|
||||
def pack(o, stream, **kwargs):
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from collections import namedtuple
|
||||
import datetime
|
||||
import struct
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
class ExtType(namedtuple("ExtType", "code data")):
|
||||
@ -157,7 +157,9 @@ class Timestamp:
|
||||
:rtype: `datetime.datetime`
|
||||
"""
|
||||
utc = datetime.timezone.utc
|
||||
return datetime.datetime.fromtimestamp(0, utc) + datetime.timedelta(seconds=self.to_unix())
|
||||
return datetime.datetime.fromtimestamp(0, utc) + datetime.timedelta(
|
||||
seconds=self.seconds, microseconds=self.nanoseconds // 1000
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def from_datetime(dt):
|
||||
@ -165,4 +167,4 @@ class Timestamp:
|
||||
|
||||
:rtype: Timestamp
|
||||
"""
|
||||
return Timestamp.from_unix(dt.timestamp())
|
||||
return Timestamp(seconds=int(dt.timestamp()), nanoseconds=dt.microsecond * 1000)
|
||||
|
||||
@ -1,27 +1,22 @@
|
||||
"""Fallback pure Python implementation of msgpack"""
|
||||
from datetime import datetime as _DateTime
|
||||
import sys
|
||||
import struct
|
||||
|
||||
import struct
|
||||
import sys
|
||||
from datetime import datetime as _DateTime
|
||||
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
# StringIO is slow on PyPy, StringIO is faster. However: PyPy's own
|
||||
# StringBuilder is fastest.
|
||||
from __pypy__ import newlist_hint
|
||||
from __pypy__.builders import BytesBuilder
|
||||
|
||||
try:
|
||||
from __pypy__.builders import BytesBuilder as StringBuilder
|
||||
except ImportError:
|
||||
from __pypy__.builders import StringBuilder
|
||||
USING_STRINGBUILDER = True
|
||||
_USING_STRINGBUILDER = True
|
||||
|
||||
class StringIO:
|
||||
class BytesIO:
|
||||
def __init__(self, s=b""):
|
||||
if s:
|
||||
self.builder = StringBuilder(len(s))
|
||||
self.builder = BytesBuilder(len(s))
|
||||
self.builder.append(s)
|
||||
else:
|
||||
self.builder = StringBuilder()
|
||||
self.builder = BytesBuilder()
|
||||
|
||||
def write(self, s):
|
||||
if isinstance(s, memoryview):
|
||||
@ -34,17 +29,17 @@ if hasattr(sys, "pypy_version_info"):
|
||||
return self.builder.build()
|
||||
|
||||
else:
|
||||
USING_STRINGBUILDER = False
|
||||
from io import BytesIO as StringIO
|
||||
from io import BytesIO
|
||||
|
||||
newlist_hint = lambda size: []
|
||||
_USING_STRINGBUILDER = False
|
||||
|
||||
def newlist_hint(size):
|
||||
return []
|
||||
|
||||
|
||||
from .exceptions import BufferFull, OutOfData, ExtraData, FormatError, StackError
|
||||
|
||||
from .exceptions import BufferFull, ExtraData, FormatError, OutOfData, StackError
|
||||
from .ext import ExtType, Timestamp
|
||||
|
||||
|
||||
EX_SKIP = 0
|
||||
EX_CONSTRUCT = 1
|
||||
EX_READ_ARRAY_HEADER = 2
|
||||
@ -231,6 +226,7 @@ class Unpacker:
|
||||
def __init__(
|
||||
self,
|
||||
file_like=None,
|
||||
*,
|
||||
read_size=0,
|
||||
use_list=True,
|
||||
raw=False,
|
||||
@ -333,6 +329,7 @@ class Unpacker:
|
||||
|
||||
# Use extend here: INPLACE_ADD += doesn't reliably typecast memoryview in jython
|
||||
self._buffer.extend(view)
|
||||
view.release()
|
||||
|
||||
def _consume(self):
|
||||
"""Gets rid of the used parts of the buffer."""
|
||||
@ -649,32 +646,13 @@ class Packer:
|
||||
The error handler for encoding unicode. (default: 'strict')
|
||||
DO NOT USE THIS!! This option is kept for very specific usage.
|
||||
|
||||
Example of streaming deserialize from file-like object::
|
||||
|
||||
unpacker = Unpacker(file_like)
|
||||
for o in unpacker:
|
||||
process(o)
|
||||
|
||||
Example of streaming deserialize from socket::
|
||||
|
||||
unpacker = Unpacker()
|
||||
while True:
|
||||
buf = sock.recv(1024**2)
|
||||
if not buf:
|
||||
break
|
||||
unpacker.feed(buf)
|
||||
for o in unpacker:
|
||||
process(o)
|
||||
|
||||
Raises ``ExtraData`` when *packed* contains extra bytes.
|
||||
Raises ``OutOfData`` when *packed* is incomplete.
|
||||
Raises ``FormatError`` when *packed* is not valid msgpack.
|
||||
Raises ``StackError`` when *packed* contains too nested.
|
||||
Other exceptions can be raised during unpacking.
|
||||
:param int buf_size:
|
||||
Internal buffer size. This option is used only for C implementation.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
default=None,
|
||||
use_single_float=False,
|
||||
autoreset=True,
|
||||
@ -682,17 +660,17 @@ class Packer:
|
||||
strict_types=False,
|
||||
datetime=False,
|
||||
unicode_errors=None,
|
||||
buf_size=None,
|
||||
):
|
||||
self._strict_types = strict_types
|
||||
self._use_float = use_single_float
|
||||
self._autoreset = autoreset
|
||||
self._use_bin_type = use_bin_type
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
self._datetime = bool(datetime)
|
||||
self._unicode_errors = unicode_errors or "strict"
|
||||
if default is not None:
|
||||
if not callable(default):
|
||||
raise TypeError("default must be callable")
|
||||
if default is not None and not callable(default):
|
||||
raise TypeError("default must be callable")
|
||||
self._default = default
|
||||
|
||||
def _pack(
|
||||
@ -823,18 +801,18 @@ class Packer:
|
||||
try:
|
||||
self._pack(obj)
|
||||
except:
|
||||
self._buffer = StringIO() # force reset
|
||||
self._buffer = BytesIO() # force reset
|
||||
raise
|
||||
if self._autoreset:
|
||||
ret = self._buffer.getvalue()
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
return ret
|
||||
|
||||
def pack_map_pairs(self, pairs):
|
||||
self._pack_map_pairs(len(pairs), pairs)
|
||||
if self._autoreset:
|
||||
ret = self._buffer.getvalue()
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
return ret
|
||||
|
||||
def pack_array_header(self, n):
|
||||
@ -843,7 +821,7 @@ class Packer:
|
||||
self._pack_array_header(n)
|
||||
if self._autoreset:
|
||||
ret = self._buffer.getvalue()
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
return ret
|
||||
|
||||
def pack_map_header(self, n):
|
||||
@ -852,7 +830,7 @@ class Packer:
|
||||
self._pack_map_header(n)
|
||||
if self._autoreset:
|
||||
ret = self._buffer.getvalue()
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
return ret
|
||||
|
||||
def pack_ext_type(self, typecode, data):
|
||||
@ -941,11 +919,11 @@ class Packer:
|
||||
|
||||
This method is useful only when autoreset=False.
|
||||
"""
|
||||
self._buffer = StringIO()
|
||||
self._buffer = BytesIO()
|
||||
|
||||
def getbuffer(self):
|
||||
"""Return view of internal buffer."""
|
||||
if USING_STRINGBUILDER:
|
||||
if _USING_STRINGBUILDER:
|
||||
return memoryview(self.bytes())
|
||||
else:
|
||||
return self._buffer.getbuffer()
|
||||
|
||||
@ -6,10 +6,10 @@ __title__ = "packaging"
|
||||
__summary__ = "Core utilities for Python packages"
|
||||
__uri__ = "https://github.com/pypa/packaging"
|
||||
|
||||
__version__ = "24.1"
|
||||
__version__ = "24.2"
|
||||
|
||||
__author__ = "Donald Stufft and individual contributors"
|
||||
__email__ = "donald@stufft.io"
|
||||
|
||||
__license__ = "BSD-2-Clause or Apache-2.0"
|
||||
__copyright__ = "2014 %s" % __author__
|
||||
__copyright__ = f"2014 {__author__}"
|
||||
|
||||
@ -48,8 +48,8 @@ class ELFFile:
|
||||
|
||||
try:
|
||||
ident = self._read("16B")
|
||||
except struct.error:
|
||||
raise ELFInvalid("unable to parse identification")
|
||||
except struct.error as e:
|
||||
raise ELFInvalid("unable to parse identification") from e
|
||||
magic = bytes(ident[:4])
|
||||
if magic != b"\x7fELF":
|
||||
raise ELFInvalid(f"invalid magic: {magic!r}")
|
||||
@ -67,11 +67,11 @@ class ELFFile:
|
||||
(2, 1): ("<HHIQQQIHHH", "<IIQQQQQQ", (0, 2, 5)), # 64-bit LSB.
|
||||
(2, 2): (">HHIQQQIHHH", ">IIQQQQQQ", (0, 2, 5)), # 64-bit MSB.
|
||||
}[(self.capacity, self.encoding)]
|
||||
except KeyError:
|
||||
except KeyError as e:
|
||||
raise ELFInvalid(
|
||||
f"unrecognized capacity ({self.capacity}) or "
|
||||
f"encoding ({self.encoding})"
|
||||
)
|
||||
) from e
|
||||
|
||||
try:
|
||||
(
|
||||
|
||||
@ -164,6 +164,7 @@ def _parse_glibc_version(version_str: str) -> tuple[int, int]:
|
||||
f"Expected glibc version with 2 components major.minor,"
|
||||
f" got: {version_str}",
|
||||
RuntimeWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return -1, -1
|
||||
return int(m.group("major")), int(m.group("minor"))
|
||||
|
||||
@ -18,9 +18,9 @@ from .utils import canonicalize_name
|
||||
|
||||
__all__ = [
|
||||
"InvalidMarker",
|
||||
"Marker",
|
||||
"UndefinedComparison",
|
||||
"UndefinedEnvironmentName",
|
||||
"Marker",
|
||||
"default_environment",
|
||||
]
|
||||
|
||||
@ -232,7 +232,7 @@ def _evaluate_markers(markers: MarkerList, environment: dict[str, str]) -> bool:
|
||||
|
||||
|
||||
def format_full_version(info: sys._version_info) -> str:
|
||||
version = "{0.major}.{0.minor}.{0.micro}".format(info)
|
||||
version = f"{info.major}.{info.minor}.{info.micro}"
|
||||
kind = info.releaselevel
|
||||
if kind != "final":
|
||||
version += kind[0] + str(info.serial)
|
||||
@ -309,12 +309,6 @@ class Marker:
|
||||
"""
|
||||
current_environment = cast("dict[str, str]", default_environment())
|
||||
current_environment["extra"] = ""
|
||||
# Work around platform.python_version() returning something that is not PEP 440
|
||||
# compliant for non-tagged Python builds. We preserve default_environment()'s
|
||||
# behavior of returning platform.python_version() verbatim, and leave it to the
|
||||
# caller to provide a syntactically valid version if they want to override it.
|
||||
if current_environment["python_full_version"].endswith("+"):
|
||||
current_environment["python_full_version"] += "local"
|
||||
if environment is not None:
|
||||
current_environment.update(environment)
|
||||
# The API used to allow setting extra to None. We need to handle this
|
||||
@ -322,4 +316,16 @@ class Marker:
|
||||
if current_environment["extra"] is None:
|
||||
current_environment["extra"] = ""
|
||||
|
||||
return _evaluate_markers(self._markers, current_environment)
|
||||
return _evaluate_markers(
|
||||
self._markers, _repair_python_full_version(current_environment)
|
||||
)
|
||||
|
||||
|
||||
def _repair_python_full_version(env: dict[str, str]) -> dict[str, str]:
|
||||
"""
|
||||
Work around platform.python_version() returning something that is not PEP 440
|
||||
compliant for non-tagged Python builds.
|
||||
"""
|
||||
if env["python_full_version"].endswith("+"):
|
||||
env["python_full_version"] += "local"
|
||||
return env
|
||||
|
||||
@ -5,6 +5,8 @@ import email.header
|
||||
import email.message
|
||||
import email.parser
|
||||
import email.policy
|
||||
import pathlib
|
||||
import sys
|
||||
import typing
|
||||
from typing import (
|
||||
Any,
|
||||
@ -15,15 +17,16 @@ from typing import (
|
||||
cast,
|
||||
)
|
||||
|
||||
from . import requirements, specifiers, utils
|
||||
from . import licenses, requirements, specifiers, utils
|
||||
from . import version as version_module
|
||||
from .licenses import NormalizedLicenseExpression
|
||||
|
||||
T = typing.TypeVar("T")
|
||||
|
||||
|
||||
try:
|
||||
ExceptionGroup
|
||||
except NameError: # pragma: no cover
|
||||
if sys.version_info >= (3, 11): # pragma: no cover
|
||||
ExceptionGroup = ExceptionGroup
|
||||
else: # pragma: no cover
|
||||
|
||||
class ExceptionGroup(Exception):
|
||||
"""A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11.
|
||||
@ -42,9 +45,6 @@ except NameError: # pragma: no cover
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})"
|
||||
|
||||
else: # pragma: no cover
|
||||
ExceptionGroup = ExceptionGroup
|
||||
|
||||
|
||||
class InvalidMetadata(ValueError):
|
||||
"""A metadata field contains invalid data."""
|
||||
@ -128,6 +128,10 @@ class RawMetadata(TypedDict, total=False):
|
||||
# No new fields were added in PEP 685, just some edge case were
|
||||
# tightened up to provide better interoptability.
|
||||
|
||||
# Metadata 2.4 - PEP 639
|
||||
license_expression: str
|
||||
license_files: list[str]
|
||||
|
||||
|
||||
_STRING_FIELDS = {
|
||||
"author",
|
||||
@ -137,6 +141,7 @@ _STRING_FIELDS = {
|
||||
"download_url",
|
||||
"home_page",
|
||||
"license",
|
||||
"license_expression",
|
||||
"maintainer",
|
||||
"maintainer_email",
|
||||
"metadata_version",
|
||||
@ -149,6 +154,7 @@ _STRING_FIELDS = {
|
||||
_LIST_FIELDS = {
|
||||
"classifiers",
|
||||
"dynamic",
|
||||
"license_files",
|
||||
"obsoletes",
|
||||
"obsoletes_dist",
|
||||
"platforms",
|
||||
@ -167,7 +173,7 @@ _DICT_FIELDS = {
|
||||
|
||||
|
||||
def _parse_keywords(data: str) -> list[str]:
|
||||
"""Split a string of comma-separate keyboards into a list of keywords."""
|
||||
"""Split a string of comma-separated keywords into a list of keywords."""
|
||||
return [k.strip() for k in data.split(",")]
|
||||
|
||||
|
||||
@ -216,16 +222,18 @@ def _get_payload(msg: email.message.Message, source: bytes | str) -> str:
|
||||
# If our source is a str, then our caller has managed encodings for us,
|
||||
# and we don't need to deal with it.
|
||||
if isinstance(source, str):
|
||||
payload: str = msg.get_payload()
|
||||
payload = msg.get_payload()
|
||||
assert isinstance(payload, str)
|
||||
return payload
|
||||
# If our source is a bytes, then we're managing the encoding and we need
|
||||
# to deal with it.
|
||||
else:
|
||||
bpayload: bytes = msg.get_payload(decode=True)
|
||||
bpayload = msg.get_payload(decode=True)
|
||||
assert isinstance(bpayload, bytes)
|
||||
try:
|
||||
return bpayload.decode("utf8", "strict")
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError("payload in an invalid encoding")
|
||||
except UnicodeDecodeError as exc:
|
||||
raise ValueError("payload in an invalid encoding") from exc
|
||||
|
||||
|
||||
# The various parse_FORMAT functions here are intended to be as lenient as
|
||||
@ -251,6 +259,8 @@ _EMAIL_TO_RAW_MAPPING = {
|
||||
"home-page": "home_page",
|
||||
"keywords": "keywords",
|
||||
"license": "license",
|
||||
"license-expression": "license_expression",
|
||||
"license-file": "license_files",
|
||||
"maintainer": "maintainer",
|
||||
"maintainer-email": "maintainer_email",
|
||||
"metadata-version": "metadata_version",
|
||||
@ -426,7 +436,7 @@ def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]:
|
||||
payload = _get_payload(parsed, data)
|
||||
except ValueError:
|
||||
unparsed.setdefault("description", []).append(
|
||||
parsed.get_payload(decode=isinstance(data, bytes))
|
||||
parsed.get_payload(decode=isinstance(data, bytes)) # type: ignore[call-overload]
|
||||
)
|
||||
else:
|
||||
if payload:
|
||||
@ -453,8 +463,8 @@ _NOT_FOUND = object()
|
||||
|
||||
|
||||
# Keep the two values in sync.
|
||||
_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3"]
|
||||
_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3"]
|
||||
_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"]
|
||||
_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"]
|
||||
|
||||
_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"])
|
||||
|
||||
@ -535,7 +545,7 @@ class _Validator(Generic[T]):
|
||||
except utils.InvalidName as exc:
|
||||
raise self._invalid_metadata(
|
||||
f"{value!r} is invalid for {{field}}", cause=exc
|
||||
)
|
||||
) from exc
|
||||
else:
|
||||
return value
|
||||
|
||||
@ -547,7 +557,7 @@ class _Validator(Generic[T]):
|
||||
except version_module.InvalidVersion as exc:
|
||||
raise self._invalid_metadata(
|
||||
f"{value!r} is invalid for {{field}}", cause=exc
|
||||
)
|
||||
) from exc
|
||||
|
||||
def _process_summary(self, value: str) -> str:
|
||||
"""Check the field contains no newlines."""
|
||||
@ -591,10 +601,12 @@ class _Validator(Generic[T]):
|
||||
for dynamic_field in map(str.lower, value):
|
||||
if dynamic_field in {"name", "version", "metadata-version"}:
|
||||
raise self._invalid_metadata(
|
||||
f"{value!r} is not allowed as a dynamic field"
|
||||
f"{dynamic_field!r} is not allowed as a dynamic field"
|
||||
)
|
||||
elif dynamic_field not in _EMAIL_TO_RAW_MAPPING:
|
||||
raise self._invalid_metadata(f"{value!r} is not a valid dynamic field")
|
||||
raise self._invalid_metadata(
|
||||
f"{dynamic_field!r} is not a valid dynamic field"
|
||||
)
|
||||
return list(map(str.lower, value))
|
||||
|
||||
def _process_provides_extra(
|
||||
@ -608,7 +620,7 @@ class _Validator(Generic[T]):
|
||||
except utils.InvalidName as exc:
|
||||
raise self._invalid_metadata(
|
||||
f"{name!r} is invalid for {{field}}", cause=exc
|
||||
)
|
||||
) from exc
|
||||
else:
|
||||
return normalized_names
|
||||
|
||||
@ -618,7 +630,7 @@ class _Validator(Generic[T]):
|
||||
except specifiers.InvalidSpecifier as exc:
|
||||
raise self._invalid_metadata(
|
||||
f"{value!r} is invalid for {{field}}", cause=exc
|
||||
)
|
||||
) from exc
|
||||
|
||||
def _process_requires_dist(
|
||||
self,
|
||||
@ -629,10 +641,49 @@ class _Validator(Generic[T]):
|
||||
for req in value:
|
||||
reqs.append(requirements.Requirement(req))
|
||||
except requirements.InvalidRequirement as exc:
|
||||
raise self._invalid_metadata(f"{req!r} is invalid for {{field}}", cause=exc)
|
||||
raise self._invalid_metadata(
|
||||
f"{req!r} is invalid for {{field}}", cause=exc
|
||||
) from exc
|
||||
else:
|
||||
return reqs
|
||||
|
||||
def _process_license_expression(
|
||||
self, value: str
|
||||
) -> NormalizedLicenseExpression | None:
|
||||
try:
|
||||
return licenses.canonicalize_license_expression(value)
|
||||
except ValueError as exc:
|
||||
raise self._invalid_metadata(
|
||||
f"{value!r} is invalid for {{field}}", cause=exc
|
||||
) from exc
|
||||
|
||||
def _process_license_files(self, value: list[str]) -> list[str]:
|
||||
paths = []
|
||||
for path in value:
|
||||
if ".." in path:
|
||||
raise self._invalid_metadata(
|
||||
f"{path!r} is invalid for {{field}}, "
|
||||
"parent directory indicators are not allowed"
|
||||
)
|
||||
if "*" in path:
|
||||
raise self._invalid_metadata(
|
||||
f"{path!r} is invalid for {{field}}, paths must be resolved"
|
||||
)
|
||||
if (
|
||||
pathlib.PurePosixPath(path).is_absolute()
|
||||
or pathlib.PureWindowsPath(path).is_absolute()
|
||||
):
|
||||
raise self._invalid_metadata(
|
||||
f"{path!r} is invalid for {{field}}, paths must be relative"
|
||||
)
|
||||
if pathlib.PureWindowsPath(path).as_posix() != path:
|
||||
raise self._invalid_metadata(
|
||||
f"{path!r} is invalid for {{field}}, "
|
||||
"paths must use '/' delimiter"
|
||||
)
|
||||
paths.append(path)
|
||||
return paths
|
||||
|
||||
|
||||
class Metadata:
|
||||
"""Representation of distribution metadata.
|
||||
@ -688,8 +739,8 @@ class Metadata:
|
||||
field = _RAW_TO_EMAIL_MAPPING[key]
|
||||
exc = InvalidMetadata(
|
||||
field,
|
||||
"{field} introduced in metadata version "
|
||||
"{field_metadata_version}, not {metadata_version}",
|
||||
f"{field} introduced in metadata version "
|
||||
f"{field_metadata_version}, not {metadata_version}",
|
||||
)
|
||||
exceptions.append(exc)
|
||||
continue
|
||||
@ -733,6 +784,8 @@ class Metadata:
|
||||
metadata_version: _Validator[_MetadataVersion] = _Validator()
|
||||
""":external:ref:`core-metadata-metadata-version`
|
||||
(required; validated to be a valid metadata version)"""
|
||||
# `name` is not normalized/typed to NormalizedName so as to provide access to
|
||||
# the original/raw name.
|
||||
name: _Validator[str] = _Validator()
|
||||
""":external:ref:`core-metadata-name`
|
||||
(required; validated using :func:`~packaging.utils.canonicalize_name` and its
|
||||
@ -770,6 +823,12 @@ class Metadata:
|
||||
""":external:ref:`core-metadata-maintainer-email`"""
|
||||
license: _Validator[str | None] = _Validator()
|
||||
""":external:ref:`core-metadata-license`"""
|
||||
license_expression: _Validator[NormalizedLicenseExpression | None] = _Validator(
|
||||
added="2.4"
|
||||
)
|
||||
""":external:ref:`core-metadata-license-expression`"""
|
||||
license_files: _Validator[list[str] | None] = _Validator(added="2.4")
|
||||
""":external:ref:`core-metadata-license-file`"""
|
||||
classifiers: _Validator[list[str] | None] = _Validator(added="1.1")
|
||||
""":external:ref:`core-metadata-classifier`"""
|
||||
requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator(
|
||||
|
||||
@ -234,7 +234,7 @@ class Specifier(BaseSpecifier):
|
||||
"""
|
||||
match = self._regex.search(spec)
|
||||
if not match:
|
||||
raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
|
||||
raise InvalidSpecifier(f"Invalid specifier: {spec!r}")
|
||||
|
||||
self._spec: tuple[str, str] = (
|
||||
match.group("operator").strip(),
|
||||
@ -256,7 +256,7 @@ class Specifier(BaseSpecifier):
|
||||
# operators, and if they are if they are including an explicit
|
||||
# prerelease.
|
||||
operator, version = self._spec
|
||||
if operator in ["==", ">=", "<=", "~=", "==="]:
|
||||
if operator in ["==", ">=", "<=", "~=", "===", ">", "<"]:
|
||||
# The == specifier can include a trailing .*, if it does we
|
||||
# want to remove before parsing.
|
||||
if operator == "==" and version.endswith(".*"):
|
||||
@ -694,12 +694,18 @@ class SpecifierSet(BaseSpecifier):
|
||||
specifiers (``>=3.0,!=3.1``), or no specifier at all.
|
||||
"""
|
||||
|
||||
def __init__(self, specifiers: str = "", prereleases: bool | None = None) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
specifiers: str | Iterable[Specifier] = "",
|
||||
prereleases: bool | None = None,
|
||||
) -> None:
|
||||
"""Initialize a SpecifierSet instance.
|
||||
|
||||
:param specifiers:
|
||||
The string representation of a specifier or a comma-separated list of
|
||||
specifiers which will be parsed and normalized before use.
|
||||
May also be an iterable of ``Specifier`` instances, which will be used
|
||||
as is.
|
||||
:param prereleases:
|
||||
This tells the SpecifierSet if it should accept prerelease versions if
|
||||
applicable or not. The default of ``None`` will autodetect it from the
|
||||
@ -710,12 +716,17 @@ class SpecifierSet(BaseSpecifier):
|
||||
raised.
|
||||
"""
|
||||
|
||||
# Split on `,` to break each individual specifier into it's own item, and
|
||||
# strip each item to remove leading/trailing whitespace.
|
||||
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
||||
if isinstance(specifiers, str):
|
||||
# Split on `,` to break each individual specifier into its own item, and
|
||||
# strip each item to remove leading/trailing whitespace.
|
||||
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
||||
|
||||
# Make each individual specifier a Specifier and save in a frozen set for later.
|
||||
self._specs = frozenset(map(Specifier, split_specifiers))
|
||||
# Make each individual specifier a Specifier and save in a frozen set
|
||||
# for later.
|
||||
self._specs = frozenset(map(Specifier, split_specifiers))
|
||||
else:
|
||||
# Save the supplied specifiers in a frozen set.
|
||||
self._specs = frozenset(specifiers)
|
||||
|
||||
# Store our prereleases value so we can use it later to determine if
|
||||
# we accept prereleases or not.
|
||||
|
||||
@ -47,7 +47,7 @@ class Tag:
|
||||
is also supported.
|
||||
"""
|
||||
|
||||
__slots__ = ["_interpreter", "_abi", "_platform", "_hash"]
|
||||
__slots__ = ["_abi", "_hash", "_interpreter", "_platform"]
|
||||
|
||||
def __init__(self, interpreter: str, abi: str, platform: str) -> None:
|
||||
self._interpreter = interpreter.lower()
|
||||
@ -235,9 +235,8 @@ def cpython_tags(
|
||||
if use_abi3:
|
||||
for minor_version in range(python_version[1] - 1, 1, -1):
|
||||
for platform_ in platforms:
|
||||
interpreter = "cp{version}".format(
|
||||
version=_version_nodot((python_version[0], minor_version))
|
||||
)
|
||||
version = _version_nodot((python_version[0], minor_version))
|
||||
interpreter = f"cp{version}"
|
||||
yield Tag(interpreter, "abi3", platform_)
|
||||
|
||||
|
||||
@ -435,24 +434,22 @@ def mac_platforms(
|
||||
if (10, 0) <= version and version < (11, 0):
|
||||
# Prior to Mac OS 11, each yearly release of Mac OS bumped the
|
||||
# "minor" version number. The major version was always 10.
|
||||
major_version = 10
|
||||
for minor_version in range(version[1], -1, -1):
|
||||
compat_version = 10, minor_version
|
||||
compat_version = major_version, minor_version
|
||||
binary_formats = _mac_binary_formats(compat_version, arch)
|
||||
for binary_format in binary_formats:
|
||||
yield "macosx_{major}_{minor}_{binary_format}".format(
|
||||
major=10, minor=minor_version, binary_format=binary_format
|
||||
)
|
||||
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
||||
|
||||
if version >= (11, 0):
|
||||
# Starting with Mac OS 11, each yearly release bumps the major version
|
||||
# number. The minor versions are now the midyear updates.
|
||||
minor_version = 0
|
||||
for major_version in range(version[0], 10, -1):
|
||||
compat_version = major_version, 0
|
||||
compat_version = major_version, minor_version
|
||||
binary_formats = _mac_binary_formats(compat_version, arch)
|
||||
for binary_format in binary_formats:
|
||||
yield "macosx_{major}_{minor}_{binary_format}".format(
|
||||
major=major_version, minor=0, binary_format=binary_format
|
||||
)
|
||||
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
||||
|
||||
if version >= (11, 0):
|
||||
# Mac OS 11 on x86_64 is compatible with binaries from previous releases.
|
||||
@ -462,25 +459,18 @@ def mac_platforms(
|
||||
# However, the "universal2" binary format can have a
|
||||
# macOS version earlier than 11.0 when the x86_64 part of the binary supports
|
||||
# that version of macOS.
|
||||
major_version = 10
|
||||
if arch == "x86_64":
|
||||
for minor_version in range(16, 3, -1):
|
||||
compat_version = 10, minor_version
|
||||
compat_version = major_version, minor_version
|
||||
binary_formats = _mac_binary_formats(compat_version, arch)
|
||||
for binary_format in binary_formats:
|
||||
yield "macosx_{major}_{minor}_{binary_format}".format(
|
||||
major=compat_version[0],
|
||||
minor=compat_version[1],
|
||||
binary_format=binary_format,
|
||||
)
|
||||
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
||||
else:
|
||||
for minor_version in range(16, 3, -1):
|
||||
compat_version = 10, minor_version
|
||||
compat_version = major_version, minor_version
|
||||
binary_format = "universal2"
|
||||
yield "macosx_{major}_{minor}_{binary_format}".format(
|
||||
major=compat_version[0],
|
||||
minor=compat_version[1],
|
||||
binary_format=binary_format,
|
||||
)
|
||||
yield f"macosx_{major_version}_{minor_version}_{binary_format}"
|
||||
|
||||
|
||||
def ios_platforms(
|
||||
@ -500,7 +490,7 @@ def ios_platforms(
|
||||
# if iOS is the current platform, ios_ver *must* be defined. However,
|
||||
# it won't exist for CPython versions before 3.13, which causes a mypy
|
||||
# error.
|
||||
_, release, _, _ = platform.ios_ver() # type: ignore[attr-defined]
|
||||
_, release, _, _ = platform.ios_ver() # type: ignore[attr-defined, unused-ignore]
|
||||
version = cast("AppleVersion", tuple(map(int, release.split(".")[:2])))
|
||||
|
||||
if multiarch is None:
|
||||
|
||||
@ -4,11 +4,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import re
|
||||
from typing import NewType, Tuple, Union, cast
|
||||
|
||||
from .tags import Tag, parse_tag
|
||||
from .version import InvalidVersion, Version
|
||||
from .version import InvalidVersion, Version, _TrimmedRelease
|
||||
|
||||
BuildTag = Union[Tuple[()], Tuple[int, str]]
|
||||
NormalizedName = NewType("NormalizedName", str)
|
||||
@ -54,52 +55,40 @@ def is_normalized_name(name: str) -> bool:
|
||||
return _normalized_regex.match(name) is not None
|
||||
|
||||
|
||||
@functools.singledispatch
|
||||
def canonicalize_version(
|
||||
version: Version | str, *, strip_trailing_zero: bool = True
|
||||
) -> str:
|
||||
"""
|
||||
This is very similar to Version.__str__, but has one subtle difference
|
||||
with the way it handles the release segment.
|
||||
Return a canonical form of a version as a string.
|
||||
|
||||
>>> canonicalize_version('1.0.1')
|
||||
'1.0.1'
|
||||
|
||||
Per PEP 625, versions may have multiple canonical forms, differing
|
||||
only by trailing zeros.
|
||||
|
||||
>>> canonicalize_version('1.0.0')
|
||||
'1'
|
||||
>>> canonicalize_version('1.0.0', strip_trailing_zero=False)
|
||||
'1.0.0'
|
||||
|
||||
Invalid versions are returned unaltered.
|
||||
|
||||
>>> canonicalize_version('foo bar baz')
|
||||
'foo bar baz'
|
||||
"""
|
||||
if isinstance(version, str):
|
||||
try:
|
||||
parsed = Version(version)
|
||||
except InvalidVersion:
|
||||
# Legacy versions cannot be normalized
|
||||
return version
|
||||
else:
|
||||
parsed = version
|
||||
return str(_TrimmedRelease(str(version)) if strip_trailing_zero else version)
|
||||
|
||||
parts = []
|
||||
|
||||
# Epoch
|
||||
if parsed.epoch != 0:
|
||||
parts.append(f"{parsed.epoch}!")
|
||||
|
||||
# Release segment
|
||||
release_segment = ".".join(str(x) for x in parsed.release)
|
||||
if strip_trailing_zero:
|
||||
# NB: This strips trailing '.0's to normalize
|
||||
release_segment = re.sub(r"(\.0)+$", "", release_segment)
|
||||
parts.append(release_segment)
|
||||
|
||||
# Pre-release
|
||||
if parsed.pre is not None:
|
||||
parts.append("".join(str(x) for x in parsed.pre))
|
||||
|
||||
# Post-release
|
||||
if parsed.post is not None:
|
||||
parts.append(f".post{parsed.post}")
|
||||
|
||||
# Development release
|
||||
if parsed.dev is not None:
|
||||
parts.append(f".dev{parsed.dev}")
|
||||
|
||||
# Local version segment
|
||||
if parsed.local is not None:
|
||||
parts.append(f"+{parsed.local}")
|
||||
|
||||
return "".join(parts)
|
||||
@canonicalize_version.register
|
||||
def _(version: str, *, strip_trailing_zero: bool = True) -> str:
|
||||
try:
|
||||
parsed = Version(version)
|
||||
except InvalidVersion:
|
||||
# Legacy versions cannot be normalized
|
||||
return version
|
||||
return canonicalize_version(parsed, strip_trailing_zero=strip_trailing_zero)
|
||||
|
||||
|
||||
def parse_wheel_filename(
|
||||
@ -107,28 +96,28 @@ def parse_wheel_filename(
|
||||
) -> tuple[NormalizedName, Version, BuildTag, frozenset[Tag]]:
|
||||
if not filename.endswith(".whl"):
|
||||
raise InvalidWheelFilename(
|
||||
f"Invalid wheel filename (extension must be '.whl'): {filename}"
|
||||
f"Invalid wheel filename (extension must be '.whl'): {filename!r}"
|
||||
)
|
||||
|
||||
filename = filename[:-4]
|
||||
dashes = filename.count("-")
|
||||
if dashes not in (4, 5):
|
||||
raise InvalidWheelFilename(
|
||||
f"Invalid wheel filename (wrong number of parts): {filename}"
|
||||
f"Invalid wheel filename (wrong number of parts): {filename!r}"
|
||||
)
|
||||
|
||||
parts = filename.split("-", dashes - 2)
|
||||
name_part = parts[0]
|
||||
# See PEP 427 for the rules on escaping the project name.
|
||||
if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None:
|
||||
raise InvalidWheelFilename(f"Invalid project name: {filename}")
|
||||
raise InvalidWheelFilename(f"Invalid project name: {filename!r}")
|
||||
name = canonicalize_name(name_part)
|
||||
|
||||
try:
|
||||
version = Version(parts[1])
|
||||
except InvalidVersion as e:
|
||||
raise InvalidWheelFilename(
|
||||
f"Invalid wheel filename (invalid version): {filename}"
|
||||
f"Invalid wheel filename (invalid version): {filename!r}"
|
||||
) from e
|
||||
|
||||
if dashes == 5:
|
||||
@ -136,7 +125,7 @@ def parse_wheel_filename(
|
||||
build_match = _build_tag_regex.match(build_part)
|
||||
if build_match is None:
|
||||
raise InvalidWheelFilename(
|
||||
f"Invalid build number: {build_part} in '{filename}'"
|
||||
f"Invalid build number: {build_part} in {filename!r}"
|
||||
)
|
||||
build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2)))
|
||||
else:
|
||||
@ -153,14 +142,14 @@ def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]:
|
||||
else:
|
||||
raise InvalidSdistFilename(
|
||||
f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):"
|
||||
f" {filename}"
|
||||
f" {filename!r}"
|
||||
)
|
||||
|
||||
# We are requiring a PEP 440 version, which cannot contain dashes,
|
||||
# so we split on the last dash.
|
||||
name_part, sep, version_part = file_stem.rpartition("-")
|
||||
if not sep:
|
||||
raise InvalidSdistFilename(f"Invalid sdist filename: {filename}")
|
||||
raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}")
|
||||
|
||||
name = canonicalize_name(name_part)
|
||||
|
||||
@ -168,7 +157,7 @@ def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]:
|
||||
version = Version(version_part)
|
||||
except InvalidVersion as e:
|
||||
raise InvalidSdistFilename(
|
||||
f"Invalid sdist filename (invalid version): {filename}"
|
||||
f"Invalid sdist filename (invalid version): {filename!r}"
|
||||
) from e
|
||||
|
||||
return (name, version)
|
||||
|
||||
@ -15,7 +15,7 @@ from typing import Any, Callable, NamedTuple, SupportsInt, Tuple, Union
|
||||
|
||||
from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType
|
||||
|
||||
__all__ = ["VERSION_PATTERN", "parse", "Version", "InvalidVersion"]
|
||||
__all__ = ["VERSION_PATTERN", "InvalidVersion", "Version", "parse"]
|
||||
|
||||
LocalType = Tuple[Union[int, str], ...]
|
||||
|
||||
@ -199,7 +199,7 @@ class Version(_BaseVersion):
|
||||
# Validate the version and parse it into pieces
|
||||
match = self._regex.search(version)
|
||||
if not match:
|
||||
raise InvalidVersion(f"Invalid version: '{version}'")
|
||||
raise InvalidVersion(f"Invalid version: {version!r}")
|
||||
|
||||
# Store the parsed out pieces of the version
|
||||
self._version = _Version(
|
||||
@ -232,7 +232,7 @@ class Version(_BaseVersion):
|
||||
return f"<Version('{self}')>"
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""A string representation of the version that can be rounded-tripped.
|
||||
"""A string representation of the version that can be round-tripped.
|
||||
|
||||
>>> str(Version("1.0a5"))
|
||||
'1.0a5'
|
||||
@ -350,8 +350,8 @@ class Version(_BaseVersion):
|
||||
'1.2.3'
|
||||
>>> Version("1.2.3+abc").public
|
||||
'1.2.3'
|
||||
>>> Version("1.2.3+abc.dev1").public
|
||||
'1.2.3'
|
||||
>>> Version("1!1.2.3dev1+abc").public
|
||||
'1!1.2.3.dev1'
|
||||
"""
|
||||
return str(self).split("+", 1)[0]
|
||||
|
||||
@ -363,7 +363,7 @@ class Version(_BaseVersion):
|
||||
'1.2.3'
|
||||
>>> Version("1.2.3+abc").base_version
|
||||
'1.2.3'
|
||||
>>> Version("1!1.2.3+abc.dev1").base_version
|
||||
>>> Version("1!1.2.3dev1+abc").base_version
|
||||
'1!1.2.3'
|
||||
|
||||
The "base version" is the public version of the project without any pre or post
|
||||
@ -451,6 +451,23 @@ class Version(_BaseVersion):
|
||||
return self.release[2] if len(self.release) >= 3 else 0
|
||||
|
||||
|
||||
class _TrimmedRelease(Version):
|
||||
@property
|
||||
def release(self) -> tuple[int, ...]:
|
||||
"""
|
||||
Release segment without any trailing zeros.
|
||||
|
||||
>>> _TrimmedRelease('1.0.0').release
|
||||
(1,)
|
||||
>>> _TrimmedRelease('0.0').release
|
||||
(0,)
|
||||
"""
|
||||
rel = super().release
|
||||
nonzeros = (index for index, val in enumerate(rel) if val)
|
||||
last_nonzero = max(nonzeros, default=0)
|
||||
return rel[: last_nonzero + 1]
|
||||
|
||||
|
||||
def _parse_letter_version(
|
||||
letter: str | None, number: str | bytes | SupportsInt | None
|
||||
) -> tuple[str, int] | None:
|
||||
@ -476,7 +493,9 @@ def _parse_letter_version(
|
||||
letter = "post"
|
||||
|
||||
return letter, int(number)
|
||||
if not letter and number:
|
||||
|
||||
assert not letter
|
||||
if number:
|
||||
# We assume if we are given a number, but we are not given a letter
|
||||
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||
letter = "post"
|
||||
|
||||
@ -19,18 +19,18 @@ if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
|
||||
if sys.platform == "win32":
|
||||
from pip._vendor.platformdirs.windows import Windows as _Result
|
||||
elif sys.platform == "darwin":
|
||||
from pip._vendor.platformdirs.macos import MacOS as _Result
|
||||
else:
|
||||
from pip._vendor.platformdirs.unix import Unix as _Result
|
||||
|
||||
|
||||
def _set_platform_dir_class() -> type[PlatformDirsABC]:
|
||||
if sys.platform == "win32":
|
||||
from pip._vendor.platformdirs.windows import Windows as Result # noqa: PLC0415
|
||||
elif sys.platform == "darwin":
|
||||
from pip._vendor.platformdirs.macos import MacOS as Result # noqa: PLC0415
|
||||
else:
|
||||
from pip._vendor.platformdirs.unix import Unix as Result # noqa: PLC0415
|
||||
|
||||
if os.getenv("ANDROID_DATA") == "/data" and os.getenv("ANDROID_ROOT") == "/system":
|
||||
if os.getenv("SHELL") or os.getenv("PREFIX"):
|
||||
return Result
|
||||
return _Result
|
||||
|
||||
from pip._vendor.platformdirs.android import _android_folder # noqa: PLC0415
|
||||
|
||||
@ -39,10 +39,14 @@ def _set_platform_dir_class() -> type[PlatformDirsABC]:
|
||||
|
||||
return Android # return to avoid redefinition of a result
|
||||
|
||||
return Result
|
||||
return _Result
|
||||
|
||||
|
||||
PlatformDirs = _set_platform_dir_class() #: Currently active platform
|
||||
if TYPE_CHECKING:
|
||||
# Work around mypy issue: https://github.com/python/mypy/issues/10962
|
||||
PlatformDirs = _Result
|
||||
else:
|
||||
PlatformDirs = _set_platform_dir_class() #: Currently active platform
|
||||
AppDirs = PlatformDirs #: Backwards compatibility with appdirs
|
||||
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@ class Android(PlatformDirsABC):
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _android_folder() -> str | None: # noqa: C901, PLR0912
|
||||
def _android_folder() -> str | None: # noqa: C901
|
||||
""":return: base folder for the Android OS or None if it cannot be found"""
|
||||
result: str | None = None
|
||||
# type checker isn't happy with our "import android", just don't do this when type checking see
|
||||
|
||||
@ -91,6 +91,12 @@ class PlatformDirsABC(ABC): # noqa: PLR0904
|
||||
if self.ensure_exists:
|
||||
Path(path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _first_item_as_path_if_multipath(self, directory: str) -> Path:
|
||||
if self.multipath:
|
||||
# If multipath is True, the first path is returned.
|
||||
directory = directory.split(os.pathsep)[0]
|
||||
return Path(directory)
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def user_data_dir(self) -> str:
|
||||
|
||||
@ -4,9 +4,13 @@ from __future__ import annotations
|
||||
|
||||
import os.path
|
||||
import sys
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .api import PlatformDirsABC
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class MacOS(PlatformDirsABC):
|
||||
"""
|
||||
@ -42,6 +46,11 @@ class MacOS(PlatformDirsABC):
|
||||
return os.pathsep.join(path_list)
|
||||
return path_list[0]
|
||||
|
||||
@property
|
||||
def site_data_path(self) -> Path:
|
||||
""":return: data path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
||||
return self._first_item_as_path_if_multipath(self.site_data_dir)
|
||||
|
||||
@property
|
||||
def user_config_dir(self) -> str:
|
||||
""":return: config directory tied to the user, same as `user_data_dir`"""
|
||||
@ -74,6 +83,11 @@ class MacOS(PlatformDirsABC):
|
||||
return os.pathsep.join(path_list)
|
||||
return path_list[0]
|
||||
|
||||
@property
|
||||
def site_cache_path(self) -> Path:
|
||||
""":return: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
||||
return self._first_item_as_path_if_multipath(self.site_cache_dir)
|
||||
|
||||
@property
|
||||
def user_state_dir(self) -> str:
|
||||
""":return: state directory tied to the user, same as `user_data_dir`"""
|
||||
|
||||
@ -218,12 +218,6 @@ class Unix(PlatformDirsABC): # noqa: PLR0904
|
||||
""":return: cache path shared by users. Only return the first item, even if ``multipath`` is set to ``True``"""
|
||||
return self._first_item_as_path_if_multipath(self.site_cache_dir)
|
||||
|
||||
def _first_item_as_path_if_multipath(self, directory: str) -> Path:
|
||||
if self.multipath:
|
||||
# If multipath is True, the first path is returned.
|
||||
directory = directory.split(os.pathsep)[0]
|
||||
return Path(directory)
|
||||
|
||||
def iter_config_dirs(self) -> Iterator[str]:
|
||||
""":yield: all user and site configuration directories."""
|
||||
yield self.user_config_dir
|
||||
|
||||
@ -12,5 +12,5 @@ __version__: str
|
||||
__version_tuple__: VERSION_TUPLE
|
||||
version_tuple: VERSION_TUPLE
|
||||
|
||||
__version__ = version = '4.2.2'
|
||||
__version_tuple__ = version_tuple = (4, 2, 2)
|
||||
__version__ = version = '4.3.6'
|
||||
__version_tuple__ = version_tuple = (4, 3, 6)
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
"""Wrappers to call pyproject.toml-based build backend hooks.
|
||||
"""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from ._impl import (
|
||||
BackendInvalid,
|
||||
BackendUnavailable,
|
||||
BuildBackendHookCaller,
|
||||
HookMissing,
|
||||
@ -11,13 +12,20 @@ from ._impl import (
|
||||
quiet_subprocess_runner,
|
||||
)
|
||||
|
||||
__version__ = '1.0.0'
|
||||
__version__ = "1.2.0"
|
||||
__all__ = [
|
||||
'BackendUnavailable',
|
||||
'BackendInvalid',
|
||||
'HookMissing',
|
||||
'UnsupportedOperation',
|
||||
'default_subprocess_runner',
|
||||
'quiet_subprocess_runner',
|
||||
'BuildBackendHookCaller',
|
||||
"BackendUnavailable",
|
||||
"BackendInvalid",
|
||||
"HookMissing",
|
||||
"UnsupportedOperation",
|
||||
"default_subprocess_runner",
|
||||
"quiet_subprocess_runner",
|
||||
"BuildBackendHookCaller",
|
||||
]
|
||||
|
||||
BackendInvalid = BackendUnavailable # Deprecated alias, previously a separate exception
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._impl import SubprocessRunner
|
||||
|
||||
__all__ += ["SubprocessRunner"]
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
__all__ = ("tomllib",)
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
import tomllib
|
||||
else:
|
||||
from pip._vendor import tomli as tomllib
|
||||
@ -6,48 +6,72 @@ from contextlib import contextmanager
|
||||
from os.path import abspath
|
||||
from os.path import join as pjoin
|
||||
from subprocess import STDOUT, check_call, check_output
|
||||
from typing import TYPE_CHECKING, Any, Iterator, Mapping, Optional, Sequence
|
||||
|
||||
from ._in_process import _in_proc_script_path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Protocol
|
||||
|
||||
def write_json(obj, path, **kwargs):
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
class SubprocessRunner(Protocol):
|
||||
"""A protocol for the subprocess runner."""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
cmd: Sequence[str],
|
||||
cwd: Optional[str] = None,
|
||||
extra_environ: Optional[Mapping[str, str]] = None,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def write_json(obj: Mapping[str, Any], path: str, **kwargs) -> None:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(obj, f, **kwargs)
|
||||
|
||||
|
||||
def read_json(path):
|
||||
with open(path, encoding='utf-8') as f:
|
||||
def read_json(path: str) -> Mapping[str, Any]:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class BackendUnavailable(Exception):
|
||||
"""Will be raised if the backend cannot be imported in the hook process."""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
class BackendInvalid(Exception):
|
||||
"""Will be raised if the backend is invalid."""
|
||||
def __init__(self, backend_name, backend_path, message):
|
||||
super().__init__(message)
|
||||
def __init__(
|
||||
self,
|
||||
traceback: str,
|
||||
message: Optional[str] = None,
|
||||
backend_name: Optional[str] = None,
|
||||
backend_path: Optional[Sequence[str]] = None,
|
||||
) -> None:
|
||||
# Preserving arg order for the sake of API backward compatibility.
|
||||
self.backend_name = backend_name
|
||||
self.backend_path = backend_path
|
||||
self.traceback = traceback
|
||||
super().__init__(message or "Error while importing backend")
|
||||
|
||||
|
||||
class HookMissing(Exception):
|
||||
"""Will be raised on missing hooks (if a fallback can't be used)."""
|
||||
def __init__(self, hook_name):
|
||||
|
||||
def __init__(self, hook_name: str) -> None:
|
||||
super().__init__(hook_name)
|
||||
self.hook_name = hook_name
|
||||
|
||||
|
||||
class UnsupportedOperation(Exception):
|
||||
"""May be raised by build_sdist if the backend indicates that it can't."""
|
||||
def __init__(self, traceback):
|
||||
|
||||
def __init__(self, traceback: str) -> None:
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
def default_subprocess_runner(
|
||||
cmd: Sequence[str],
|
||||
cwd: Optional[str] = None,
|
||||
extra_environ: Optional[Mapping[str, str]] = None,
|
||||
) -> None:
|
||||
"""The default method of calling the wrapper subprocess.
|
||||
|
||||
This uses :func:`subprocess.check_call` under the hood.
|
||||
@ -59,7 +83,11 @@ def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
check_call(cmd, cwd=cwd, env=env)
|
||||
|
||||
|
||||
def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
def quiet_subprocess_runner(
|
||||
cmd: Sequence[str],
|
||||
cwd: Optional[str] = None,
|
||||
extra_environ: Optional[Mapping[str, str]] = None,
|
||||
) -> None:
|
||||
"""Call the subprocess while suppressing output.
|
||||
|
||||
This uses :func:`subprocess.check_output` under the hood.
|
||||
@ -71,7 +99,7 @@ def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None):
|
||||
check_output(cmd, cwd=cwd, env=env, stderr=STDOUT)
|
||||
|
||||
|
||||
def norm_and_check(source_tree, requested):
|
||||
def norm_and_check(source_tree: str, requested: str) -> str:
|
||||
"""Normalise and check a backend path.
|
||||
|
||||
Ensure that the requested backend path is specified as a relative path,
|
||||
@ -96,17 +124,16 @@ def norm_and_check(source_tree, requested):
|
||||
|
||||
|
||||
class BuildBackendHookCaller:
|
||||
"""A wrapper to call the build backend hooks for a source directory.
|
||||
"""
|
||||
"""A wrapper to call the build backend hooks for a source directory."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source_dir,
|
||||
build_backend,
|
||||
backend_path=None,
|
||||
runner=None,
|
||||
python_executable=None,
|
||||
):
|
||||
self,
|
||||
source_dir: str,
|
||||
build_backend: str,
|
||||
backend_path: Optional[Sequence[str]] = None,
|
||||
runner: Optional["SubprocessRunner"] = None,
|
||||
python_executable: Optional[str] = None,
|
||||
) -> None:
|
||||
"""
|
||||
:param source_dir: The source directory to invoke the build backend for
|
||||
:param build_backend: The build backend spec
|
||||
@ -121,9 +148,7 @@ class BuildBackendHookCaller:
|
||||
self.source_dir = abspath(source_dir)
|
||||
self.build_backend = build_backend
|
||||
if backend_path:
|
||||
backend_path = [
|
||||
norm_and_check(self.source_dir, p) for p in backend_path
|
||||
]
|
||||
backend_path = [norm_and_check(self.source_dir, p) for p in backend_path]
|
||||
self.backend_path = backend_path
|
||||
self._subprocess_runner = runner
|
||||
if not python_executable:
|
||||
@ -131,10 +156,12 @@ class BuildBackendHookCaller:
|
||||
self.python_executable = python_executable
|
||||
|
||||
@contextmanager
|
||||
def subprocess_runner(self, runner):
|
||||
def subprocess_runner(self, runner: "SubprocessRunner") -> Iterator[None]:
|
||||
"""A context manager for temporarily overriding the default
|
||||
:ref:`subprocess runner <Subprocess Runners>`.
|
||||
|
||||
:param runner: The new subprocess runner to use within the context.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
hook_caller = BuildBackendHookCaller(...)
|
||||
@ -148,33 +175,44 @@ class BuildBackendHookCaller:
|
||||
finally:
|
||||
self._subprocess_runner = prev
|
||||
|
||||
def _supported_features(self):
|
||||
def _supported_features(self) -> Sequence[str]:
|
||||
"""Return the list of optional features supported by the backend."""
|
||||
return self._call_hook('_supported_features', {})
|
||||
return self._call_hook("_supported_features", {})
|
||||
|
||||
def get_requires_for_build_wheel(self, config_settings=None):
|
||||
def get_requires_for_build_wheel(
|
||||
self,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
) -> Sequence[str]:
|
||||
"""Get additional dependencies required for building a wheel.
|
||||
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:returns: A list of :pep:`dependency specifiers <508>`.
|
||||
:rtype: list[str]
|
||||
|
||||
.. admonition:: Fallback
|
||||
|
||||
If the build backend does not defined a hook with this name, an
|
||||
empty list will be returned.
|
||||
"""
|
||||
return self._call_hook('get_requires_for_build_wheel', {
|
||||
'config_settings': config_settings
|
||||
})
|
||||
return self._call_hook(
|
||||
"get_requires_for_build_wheel", {"config_settings": config_settings}
|
||||
)
|
||||
|
||||
def prepare_metadata_for_build_wheel(
|
||||
self, metadata_directory, config_settings=None,
|
||||
_allow_fallback=True):
|
||||
self,
|
||||
metadata_directory: str,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
_allow_fallback: bool = True,
|
||||
) -> str:
|
||||
"""Prepare a ``*.dist-info`` folder with metadata for this project.
|
||||
|
||||
:param metadata_directory: The directory to write the metadata to
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:param _allow_fallback:
|
||||
Whether to allow the fallback to building a wheel and extracting
|
||||
the metadata from it. Should be passed as a keyword argument only.
|
||||
|
||||
:returns: Name of the newly created subfolder within
|
||||
``metadata_directory``, containing the metadata.
|
||||
:rtype: str
|
||||
|
||||
.. admonition:: Fallback
|
||||
|
||||
@ -183,17 +221,26 @@ class BuildBackendHookCaller:
|
||||
wheel via the ``build_wheel`` hook and the dist-info extracted from
|
||||
that will be returned.
|
||||
"""
|
||||
return self._call_hook('prepare_metadata_for_build_wheel', {
|
||||
'metadata_directory': abspath(metadata_directory),
|
||||
'config_settings': config_settings,
|
||||
'_allow_fallback': _allow_fallback,
|
||||
})
|
||||
return self._call_hook(
|
||||
"prepare_metadata_for_build_wheel",
|
||||
{
|
||||
"metadata_directory": abspath(metadata_directory),
|
||||
"config_settings": config_settings,
|
||||
"_allow_fallback": _allow_fallback,
|
||||
},
|
||||
)
|
||||
|
||||
def build_wheel(
|
||||
self, wheel_directory, config_settings=None,
|
||||
metadata_directory=None):
|
||||
self,
|
||||
wheel_directory: str,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
metadata_directory: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Build a wheel from this project.
|
||||
|
||||
:param wheel_directory: The directory to write the wheel to
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:param metadata_directory: The directory to reuse existing metadata from
|
||||
:returns:
|
||||
The name of the newly created wheel within ``wheel_directory``.
|
||||
|
||||
@ -206,35 +253,48 @@ class BuildBackendHookCaller:
|
||||
"""
|
||||
if metadata_directory is not None:
|
||||
metadata_directory = abspath(metadata_directory)
|
||||
return self._call_hook('build_wheel', {
|
||||
'wheel_directory': abspath(wheel_directory),
|
||||
'config_settings': config_settings,
|
||||
'metadata_directory': metadata_directory,
|
||||
})
|
||||
return self._call_hook(
|
||||
"build_wheel",
|
||||
{
|
||||
"wheel_directory": abspath(wheel_directory),
|
||||
"config_settings": config_settings,
|
||||
"metadata_directory": metadata_directory,
|
||||
},
|
||||
)
|
||||
|
||||
def get_requires_for_build_editable(self, config_settings=None):
|
||||
def get_requires_for_build_editable(
|
||||
self,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
) -> Sequence[str]:
|
||||
"""Get additional dependencies required for building an editable wheel.
|
||||
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:returns: A list of :pep:`dependency specifiers <508>`.
|
||||
:rtype: list[str]
|
||||
|
||||
.. admonition:: Fallback
|
||||
|
||||
If the build backend does not defined a hook with this name, an
|
||||
empty list will be returned.
|
||||
"""
|
||||
return self._call_hook('get_requires_for_build_editable', {
|
||||
'config_settings': config_settings
|
||||
})
|
||||
return self._call_hook(
|
||||
"get_requires_for_build_editable", {"config_settings": config_settings}
|
||||
)
|
||||
|
||||
def prepare_metadata_for_build_editable(
|
||||
self, metadata_directory, config_settings=None,
|
||||
_allow_fallback=True):
|
||||
self,
|
||||
metadata_directory: str,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
_allow_fallback: bool = True,
|
||||
) -> Optional[str]:
|
||||
"""Prepare a ``*.dist-info`` folder with metadata for this project.
|
||||
|
||||
:param metadata_directory: The directory to write the metadata to
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:param _allow_fallback:
|
||||
Whether to allow the fallback to building a wheel and extracting
|
||||
the metadata from it. Should be passed as a keyword argument only.
|
||||
:returns: Name of the newly created subfolder within
|
||||
``metadata_directory``, containing the metadata.
|
||||
:rtype: str
|
||||
|
||||
.. admonition:: Fallback
|
||||
|
||||
@ -243,17 +303,26 @@ class BuildBackendHookCaller:
|
||||
wheel via the ``build_editable`` hook and the dist-info
|
||||
extracted from that will be returned.
|
||||
"""
|
||||
return self._call_hook('prepare_metadata_for_build_editable', {
|
||||
'metadata_directory': abspath(metadata_directory),
|
||||
'config_settings': config_settings,
|
||||
'_allow_fallback': _allow_fallback,
|
||||
})
|
||||
return self._call_hook(
|
||||
"prepare_metadata_for_build_editable",
|
||||
{
|
||||
"metadata_directory": abspath(metadata_directory),
|
||||
"config_settings": config_settings,
|
||||
"_allow_fallback": _allow_fallback,
|
||||
},
|
||||
)
|
||||
|
||||
def build_editable(
|
||||
self, wheel_directory, config_settings=None,
|
||||
metadata_directory=None):
|
||||
self,
|
||||
wheel_directory: str,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
metadata_directory: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Build an editable wheel from this project.
|
||||
|
||||
:param wheel_directory: The directory to write the wheel to
|
||||
:param config_settings: The configuration settings for the build backend
|
||||
:param metadata_directory: The directory to reuse existing metadata from
|
||||
:returns:
|
||||
The name of the newly created wheel within ``wheel_directory``.
|
||||
|
||||
@ -267,43 +336,55 @@ class BuildBackendHookCaller:
|
||||
"""
|
||||
if metadata_directory is not None:
|
||||
metadata_directory = abspath(metadata_directory)
|
||||
return self._call_hook('build_editable', {
|
||||
'wheel_directory': abspath(wheel_directory),
|
||||
'config_settings': config_settings,
|
||||
'metadata_directory': metadata_directory,
|
||||
})
|
||||
return self._call_hook(
|
||||
"build_editable",
|
||||
{
|
||||
"wheel_directory": abspath(wheel_directory),
|
||||
"config_settings": config_settings,
|
||||
"metadata_directory": metadata_directory,
|
||||
},
|
||||
)
|
||||
|
||||
def get_requires_for_build_sdist(self, config_settings=None):
|
||||
def get_requires_for_build_sdist(
|
||||
self,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
) -> Sequence[str]:
|
||||
"""Get additional dependencies required for building an sdist.
|
||||
|
||||
:returns: A list of :pep:`dependency specifiers <508>`.
|
||||
:rtype: list[str]
|
||||
"""
|
||||
return self._call_hook('get_requires_for_build_sdist', {
|
||||
'config_settings': config_settings
|
||||
})
|
||||
return self._call_hook(
|
||||
"get_requires_for_build_sdist", {"config_settings": config_settings}
|
||||
)
|
||||
|
||||
def build_sdist(self, sdist_directory, config_settings=None):
|
||||
def build_sdist(
|
||||
self,
|
||||
sdist_directory: str,
|
||||
config_settings: Optional[Mapping[str, Any]] = None,
|
||||
) -> str:
|
||||
"""Build an sdist from this project.
|
||||
|
||||
:returns:
|
||||
The name of the newly created sdist within ``wheel_directory``.
|
||||
"""
|
||||
return self._call_hook('build_sdist', {
|
||||
'sdist_directory': abspath(sdist_directory),
|
||||
'config_settings': config_settings,
|
||||
})
|
||||
return self._call_hook(
|
||||
"build_sdist",
|
||||
{
|
||||
"sdist_directory": abspath(sdist_directory),
|
||||
"config_settings": config_settings,
|
||||
},
|
||||
)
|
||||
|
||||
def _call_hook(self, hook_name, kwargs):
|
||||
extra_environ = {'PEP517_BUILD_BACKEND': self.build_backend}
|
||||
def _call_hook(self, hook_name: str, kwargs: Mapping[str, Any]) -> Any:
|
||||
extra_environ = {"_PYPROJECT_HOOKS_BUILD_BACKEND": self.build_backend}
|
||||
|
||||
if self.backend_path:
|
||||
backend_path = os.pathsep.join(self.backend_path)
|
||||
extra_environ['PEP517_BACKEND_PATH'] = backend_path
|
||||
extra_environ["_PYPROJECT_HOOKS_BACKEND_PATH"] = backend_path
|
||||
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
hook_input = {'kwargs': kwargs}
|
||||
write_json(hook_input, pjoin(td, 'input.json'), indent=2)
|
||||
hook_input = {"kwargs": kwargs}
|
||||
write_json(hook_input, pjoin(td, "input.json"), indent=2)
|
||||
|
||||
# Run the hook in a subprocess
|
||||
with _in_proc_script_path() as script:
|
||||
@ -311,20 +392,19 @@ class BuildBackendHookCaller:
|
||||
self._subprocess_runner(
|
||||
[python, abspath(str(script)), hook_name, td],
|
||||
cwd=self.source_dir,
|
||||
extra_environ=extra_environ
|
||||
extra_environ=extra_environ,
|
||||
)
|
||||
|
||||
data = read_json(pjoin(td, 'output.json'))
|
||||
if data.get('unsupported'):
|
||||
raise UnsupportedOperation(data.get('traceback', ''))
|
||||
if data.get('no_backend'):
|
||||
raise BackendUnavailable(data.get('traceback', ''))
|
||||
if data.get('backend_invalid'):
|
||||
raise BackendInvalid(
|
||||
data = read_json(pjoin(td, "output.json"))
|
||||
if data.get("unsupported"):
|
||||
raise UnsupportedOperation(data.get("traceback", ""))
|
||||
if data.get("no_backend"):
|
||||
raise BackendUnavailable(
|
||||
data.get("traceback", ""),
|
||||
message=data.get("backend_error", ""),
|
||||
backend_name=self.build_backend,
|
||||
backend_path=self.backend_path,
|
||||
message=data.get('backend_error', '')
|
||||
)
|
||||
if data.get('hook_missing'):
|
||||
raise HookMissing(data.get('missing_hook_name') or hook_name)
|
||||
return data['return_val']
|
||||
if data.get("hook_missing"):
|
||||
raise HookMissing(data.get("missing_hook_name") or hook_name)
|
||||
return data["return_val"]
|
||||
|
||||
@ -11,8 +11,11 @@ try:
|
||||
except AttributeError:
|
||||
# Python 3.8 compatibility
|
||||
def _in_proc_script_path():
|
||||
return resources.path(__package__, '_in_process.py')
|
||||
return resources.path(__package__, "_in_process.py")
|
||||
|
||||
else:
|
||||
|
||||
def _in_proc_script_path():
|
||||
return resources.as_file(
|
||||
resources.files(__package__).joinpath('_in_process.py'))
|
||||
resources.files(__package__).joinpath("_in_process.py")
|
||||
)
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
It expects:
|
||||
- Command line args: hook_name, control_dir
|
||||
- Environment variables:
|
||||
PEP517_BUILD_BACKEND=entry.point:spec
|
||||
PEP517_BACKEND_PATH=paths (separated with os.pathsep)
|
||||
_PYPROJECT_HOOKS_BUILD_BACKEND=entry.point:spec
|
||||
_PYPROJECT_HOOKS_BACKEND_PATH=paths (separated with os.pathsep)
|
||||
- control_dir/input.json:
|
||||
- {"kwargs": {...}}
|
||||
|
||||
@ -21,6 +21,7 @@ import sys
|
||||
import traceback
|
||||
from glob import glob
|
||||
from importlib import import_module
|
||||
from importlib.machinery import PathFinder
|
||||
from os.path import join as pjoin
|
||||
|
||||
# This file is run as a script, and `import wrappers` is not zip-safe, so we
|
||||
@ -28,69 +29,93 @@ from os.path import join as pjoin
|
||||
|
||||
|
||||
def write_json(obj, path, **kwargs):
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(obj, f, **kwargs)
|
||||
|
||||
|
||||
def read_json(path):
|
||||
with open(path, encoding='utf-8') as f:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class BackendUnavailable(Exception):
|
||||
"""Raised if we cannot import the backend"""
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
class BackendInvalid(Exception):
|
||||
"""Raised if the backend is invalid"""
|
||||
def __init__(self, message):
|
||||
def __init__(self, message, traceback=None):
|
||||
super().__init__(message)
|
||||
self.message = message
|
||||
self.traceback = traceback
|
||||
|
||||
|
||||
class HookMissing(Exception):
|
||||
"""Raised if a hook is missing and we are not executing the fallback"""
|
||||
|
||||
def __init__(self, hook_name=None):
|
||||
super().__init__(hook_name)
|
||||
self.hook_name = hook_name
|
||||
|
||||
|
||||
def contained_in(filename, directory):
|
||||
"""Test if a file is located within the given directory."""
|
||||
filename = os.path.normcase(os.path.abspath(filename))
|
||||
directory = os.path.normcase(os.path.abspath(directory))
|
||||
return os.path.commonprefix([filename, directory]) == directory
|
||||
|
||||
|
||||
def _build_backend():
|
||||
"""Find and load the build backend"""
|
||||
# Add in-tree backend directories to the front of sys.path.
|
||||
backend_path = os.environ.get('PEP517_BACKEND_PATH')
|
||||
if backend_path:
|
||||
extra_pathitems = backend_path.split(os.pathsep)
|
||||
sys.path[:0] = extra_pathitems
|
||||
backend_path = os.environ.get("_PYPROJECT_HOOKS_BACKEND_PATH")
|
||||
ep = os.environ["_PYPROJECT_HOOKS_BUILD_BACKEND"]
|
||||
mod_path, _, obj_path = ep.partition(":")
|
||||
|
||||
if backend_path:
|
||||
# Ensure in-tree backend directories have the highest priority when importing.
|
||||
extra_pathitems = backend_path.split(os.pathsep)
|
||||
sys.meta_path.insert(0, _BackendPathFinder(extra_pathitems, mod_path))
|
||||
|
||||
ep = os.environ['PEP517_BUILD_BACKEND']
|
||||
mod_path, _, obj_path = ep.partition(':')
|
||||
try:
|
||||
obj = import_module(mod_path)
|
||||
except ImportError:
|
||||
raise BackendUnavailable(traceback.format_exc())
|
||||
|
||||
if backend_path:
|
||||
if not any(
|
||||
contained_in(obj.__file__, path)
|
||||
for path in extra_pathitems
|
||||
):
|
||||
raise BackendInvalid("Backend was not loaded from backend-path")
|
||||
msg = f"Cannot import {mod_path!r}"
|
||||
raise BackendUnavailable(msg, traceback.format_exc())
|
||||
|
||||
if obj_path:
|
||||
for path_part in obj_path.split('.'):
|
||||
for path_part in obj_path.split("."):
|
||||
obj = getattr(obj, path_part)
|
||||
return obj
|
||||
|
||||
|
||||
class _BackendPathFinder:
|
||||
"""Implements the MetaPathFinder interface to locate modules in ``backend-path``.
|
||||
|
||||
Since the environment provided by the frontend can contain all sorts of
|
||||
MetaPathFinders, the only way to ensure the backend is loaded from the
|
||||
right place is to prepend our own.
|
||||
"""
|
||||
|
||||
def __init__(self, backend_path, backend_module):
|
||||
self.backend_path = backend_path
|
||||
self.backend_module = backend_module
|
||||
self.backend_parent, _, _ = backend_module.partition(".")
|
||||
|
||||
def find_spec(self, fullname, _path, _target=None):
|
||||
if "." in fullname:
|
||||
# Rely on importlib to find nested modules based on parent's path
|
||||
return None
|
||||
|
||||
# Ignore other items in _path or sys.path and use backend_path instead:
|
||||
spec = PathFinder.find_spec(fullname, path=self.backend_path)
|
||||
if spec is None and fullname == self.backend_parent:
|
||||
# According to the spec, the backend MUST be loaded from backend-path.
|
||||
# Therefore, we can halt the import machinery and raise a clean error.
|
||||
msg = f"Cannot find module {self.backend_module!r} in {self.backend_path!r}"
|
||||
raise BackendUnavailable(msg)
|
||||
|
||||
return spec
|
||||
|
||||
if sys.version_info >= (3, 8):
|
||||
|
||||
def find_distributions(self, context=None):
|
||||
# Delayed import: Python 3.7 does not contain importlib.metadata
|
||||
from importlib.metadata import DistributionFinder, MetadataPathFinder
|
||||
|
||||
context = DistributionFinder.Context(path=self.backend_path)
|
||||
return MetadataPathFinder.find_distributions(context=context)
|
||||
|
||||
|
||||
def _supported_features():
|
||||
"""Return the list of options features supported by the backend.
|
||||
|
||||
@ -133,7 +158,8 @@ def get_requires_for_build_editable(config_settings):
|
||||
|
||||
|
||||
def prepare_metadata_for_build_wheel(
|
||||
metadata_directory, config_settings, _allow_fallback):
|
||||
metadata_directory, config_settings, _allow_fallback
|
||||
):
|
||||
"""Invoke optional prepare_metadata_for_build_wheel
|
||||
|
||||
Implements a fallback by building a wheel if the hook isn't defined,
|
||||
@ -150,12 +176,14 @@ def prepare_metadata_for_build_wheel(
|
||||
# fallback to build_wheel outside the try block to avoid exception chaining
|
||||
# which can be confusing to users and is not relevant
|
||||
whl_basename = backend.build_wheel(metadata_directory, config_settings)
|
||||
return _get_wheel_metadata_from_wheel(whl_basename, metadata_directory,
|
||||
config_settings)
|
||||
return _get_wheel_metadata_from_wheel(
|
||||
whl_basename, metadata_directory, config_settings
|
||||
)
|
||||
|
||||
|
||||
def prepare_metadata_for_build_editable(
|
||||
metadata_directory, config_settings, _allow_fallback):
|
||||
metadata_directory, config_settings, _allow_fallback
|
||||
):
|
||||
"""Invoke optional prepare_metadata_for_build_editable
|
||||
|
||||
Implements a fallback by building an editable wheel if the hook isn't
|
||||
@ -171,24 +199,24 @@ def prepare_metadata_for_build_editable(
|
||||
try:
|
||||
build_hook = backend.build_editable
|
||||
except AttributeError:
|
||||
raise HookMissing(hook_name='build_editable')
|
||||
raise HookMissing(hook_name="build_editable")
|
||||
else:
|
||||
whl_basename = build_hook(metadata_directory, config_settings)
|
||||
return _get_wheel_metadata_from_wheel(whl_basename,
|
||||
metadata_directory,
|
||||
config_settings)
|
||||
return _get_wheel_metadata_from_wheel(
|
||||
whl_basename, metadata_directory, config_settings
|
||||
)
|
||||
else:
|
||||
return hook(metadata_directory, config_settings)
|
||||
|
||||
|
||||
WHEEL_BUILT_MARKER = 'PEP517_ALREADY_BUILT_WHEEL'
|
||||
WHEEL_BUILT_MARKER = "PYPROJECT_HOOKS_ALREADY_BUILT_WHEEL"
|
||||
|
||||
|
||||
def _dist_info_files(whl_zip):
|
||||
"""Identify the .dist-info folder inside a wheel ZipFile."""
|
||||
res = []
|
||||
for path in whl_zip.namelist():
|
||||
m = re.match(r'[^/\\]+-[^/\\]+\.dist-info/', path)
|
||||
m = re.match(r"[^/\\]+-[^/\\]+\.dist-info/", path)
|
||||
if m:
|
||||
res.append(path)
|
||||
if res:
|
||||
@ -196,40 +224,41 @@ def _dist_info_files(whl_zip):
|
||||
raise Exception("No .dist-info folder found in wheel")
|
||||
|
||||
|
||||
def _get_wheel_metadata_from_wheel(
|
||||
whl_basename, metadata_directory, config_settings):
|
||||
def _get_wheel_metadata_from_wheel(whl_basename, metadata_directory, config_settings):
|
||||
"""Extract the metadata from a wheel.
|
||||
|
||||
Fallback for when the build backend does not
|
||||
define the 'get_wheel_metadata' hook.
|
||||
"""
|
||||
from zipfile import ZipFile
|
||||
with open(os.path.join(metadata_directory, WHEEL_BUILT_MARKER), 'wb'):
|
||||
|
||||
with open(os.path.join(metadata_directory, WHEEL_BUILT_MARKER), "wb"):
|
||||
pass # Touch marker file
|
||||
|
||||
whl_file = os.path.join(metadata_directory, whl_basename)
|
||||
with ZipFile(whl_file) as zipf:
|
||||
dist_info = _dist_info_files(zipf)
|
||||
zipf.extractall(path=metadata_directory, members=dist_info)
|
||||
return dist_info[0].split('/')[0]
|
||||
return dist_info[0].split("/")[0]
|
||||
|
||||
|
||||
def _find_already_built_wheel(metadata_directory):
|
||||
"""Check for a wheel already built during the get_wheel_metadata hook.
|
||||
"""
|
||||
"""Check for a wheel already built during the get_wheel_metadata hook."""
|
||||
if not metadata_directory:
|
||||
return None
|
||||
metadata_parent = os.path.dirname(metadata_directory)
|
||||
if not os.path.isfile(pjoin(metadata_parent, WHEEL_BUILT_MARKER)):
|
||||
return None
|
||||
|
||||
whl_files = glob(os.path.join(metadata_parent, '*.whl'))
|
||||
whl_files = glob(os.path.join(metadata_parent, "*.whl"))
|
||||
if not whl_files:
|
||||
print('Found wheel built marker, but no .whl files')
|
||||
print("Found wheel built marker, but no .whl files")
|
||||
return None
|
||||
if len(whl_files) > 1:
|
||||
print('Found multiple .whl files; unspecified behaviour. '
|
||||
'Will call build_wheel.')
|
||||
print(
|
||||
"Found multiple .whl files; unspecified behaviour. "
|
||||
"Will call build_wheel."
|
||||
)
|
||||
return None
|
||||
|
||||
# Exactly one .whl file
|
||||
@ -248,8 +277,9 @@ def build_wheel(wheel_directory, config_settings, metadata_directory=None):
|
||||
shutil.copy2(prebuilt_whl, wheel_directory)
|
||||
return os.path.basename(prebuilt_whl)
|
||||
|
||||
return _build_backend().build_wheel(wheel_directory, config_settings,
|
||||
metadata_directory)
|
||||
return _build_backend().build_wheel(
|
||||
wheel_directory, config_settings, metadata_directory
|
||||
)
|
||||
|
||||
|
||||
def build_editable(wheel_directory, config_settings, metadata_directory=None):
|
||||
@ -293,6 +323,7 @@ class _DummyException(Exception):
|
||||
|
||||
class GotUnsupportedOperation(Exception):
|
||||
"""For internal use when backend raises UnsupportedOperation"""
|
||||
|
||||
def __init__(self, traceback):
|
||||
self.traceback = traceback
|
||||
|
||||
@ -302,20 +333,20 @@ def build_sdist(sdist_directory, config_settings):
|
||||
backend = _build_backend()
|
||||
try:
|
||||
return backend.build_sdist(sdist_directory, config_settings)
|
||||
except getattr(backend, 'UnsupportedOperation', _DummyException):
|
||||
except getattr(backend, "UnsupportedOperation", _DummyException):
|
||||
raise GotUnsupportedOperation(traceback.format_exc())
|
||||
|
||||
|
||||
HOOK_NAMES = {
|
||||
'get_requires_for_build_wheel',
|
||||
'prepare_metadata_for_build_wheel',
|
||||
'build_wheel',
|
||||
'get_requires_for_build_editable',
|
||||
'prepare_metadata_for_build_editable',
|
||||
'build_editable',
|
||||
'get_requires_for_build_sdist',
|
||||
'build_sdist',
|
||||
'_supported_features',
|
||||
"get_requires_for_build_wheel",
|
||||
"prepare_metadata_for_build_wheel",
|
||||
"build_wheel",
|
||||
"get_requires_for_build_editable",
|
||||
"prepare_metadata_for_build_editable",
|
||||
"build_editable",
|
||||
"get_requires_for_build_sdist",
|
||||
"build_sdist",
|
||||
"_supported_features",
|
||||
}
|
||||
|
||||
|
||||
@ -326,28 +357,33 @@ def main():
|
||||
control_dir = sys.argv[2]
|
||||
if hook_name not in HOOK_NAMES:
|
||||
sys.exit("Unknown hook: %s" % hook_name)
|
||||
|
||||
# Remove the parent directory from sys.path to avoid polluting the backend
|
||||
# import namespace with this directory.
|
||||
here = os.path.dirname(__file__)
|
||||
if here in sys.path:
|
||||
sys.path.remove(here)
|
||||
|
||||
hook = globals()[hook_name]
|
||||
|
||||
hook_input = read_json(pjoin(control_dir, 'input.json'))
|
||||
hook_input = read_json(pjoin(control_dir, "input.json"))
|
||||
|
||||
json_out = {'unsupported': False, 'return_val': None}
|
||||
json_out = {"unsupported": False, "return_val": None}
|
||||
try:
|
||||
json_out['return_val'] = hook(**hook_input['kwargs'])
|
||||
json_out["return_val"] = hook(**hook_input["kwargs"])
|
||||
except BackendUnavailable as e:
|
||||
json_out['no_backend'] = True
|
||||
json_out['traceback'] = e.traceback
|
||||
except BackendInvalid as e:
|
||||
json_out['backend_invalid'] = True
|
||||
json_out['backend_error'] = e.message
|
||||
json_out["no_backend"] = True
|
||||
json_out["traceback"] = e.traceback
|
||||
json_out["backend_error"] = e.message
|
||||
except GotUnsupportedOperation as e:
|
||||
json_out['unsupported'] = True
|
||||
json_out['traceback'] = e.traceback
|
||||
json_out["unsupported"] = True
|
||||
json_out["traceback"] = e.traceback
|
||||
except HookMissing as e:
|
||||
json_out['hook_missing'] = True
|
||||
json_out['missing_hook_name'] = e.hook_name or hook_name
|
||||
json_out["hook_missing"] = True
|
||||
json_out["missing_hook_name"] = e.hook_name or hook_name
|
||||
|
||||
write_json(json_out, pjoin(control_dir, 'output.json'), indent=2)
|
||||
write_json(json_out, pjoin(control_dir, "output.json"), indent=2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@ -11,14 +11,7 @@ If you are packaging Requests, e.g., for a Linux distribution or a managed
|
||||
environment, you can change the definition of where() to return a separately
|
||||
packaged CA bundle.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
if "_PIP_STANDALONE_CERT" not in os.environ:
|
||||
from pip._vendor.certifi import where
|
||||
else:
|
||||
def where():
|
||||
return os.environ["_PIP_STANDALONE_CERT"]
|
||||
from pip._vendor.certifi import where
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(where())
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import inspect
|
||||
from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature
|
||||
from typing import Any, Collection, Iterable, Optional, Tuple, Type, Union
|
||||
|
||||
@ -46,7 +46,7 @@ class NullFile(IO[str]):
|
||||
return iter([""])
|
||||
|
||||
def __enter__(self) -> IO[str]:
|
||||
pass
|
||||
return self
|
||||
|
||||
def __exit__(
|
||||
self,
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
The API that this module wraps is documented at https://docs.microsoft.com/en-us/windows/console/console-functions
|
||||
"""
|
||||
|
||||
import ctypes
|
||||
import sys
|
||||
from typing import Any
|
||||
@ -380,7 +381,7 @@ class LegacyWindowsTerm:
|
||||
WindowsCoordinates: The current cursor position.
|
||||
"""
|
||||
coord: COORD = GetConsoleScreenBufferInfo(self._handle).dwCursorPosition
|
||||
return WindowsCoordinates(row=cast(int, coord.Y), col=cast(int, coord.X))
|
||||
return WindowsCoordinates(row=coord.Y, col=coord.X)
|
||||
|
||||
@property
|
||||
def screen_size(self) -> WindowsCoordinates:
|
||||
@ -390,9 +391,7 @@ class LegacyWindowsTerm:
|
||||
WindowsCoordinates: The width and height of the screen as WindowsCoordinates.
|
||||
"""
|
||||
screen_size: COORD = GetConsoleScreenBufferInfo(self._handle).dwSize
|
||||
return WindowsCoordinates(
|
||||
row=cast(int, screen_size.Y), col=cast(int, screen_size.X)
|
||||
)
|
||||
return WindowsCoordinates(row=screen_size.Y, col=screen_size.X)
|
||||
|
||||
def write_text(self, text: str) -> None:
|
||||
"""Write text directly to the terminal without any modification of styles
|
||||
|
||||
@ -240,6 +240,7 @@ class VerticalCenter(JupyterMixin):
|
||||
|
||||
Args:
|
||||
renderable (RenderableType): A renderable object.
|
||||
style (StyleType, optional): An optional style to apply to the background. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@ -9,6 +9,7 @@ from .text import Text
|
||||
|
||||
re_ansi = re.compile(
|
||||
r"""
|
||||
(?:\x1b[0-?])|
|
||||
(?:\x1b\](.*?)\x1b\\)|
|
||||
(?:\x1b([(@-Z\\-_]|\[[0-?]*[ -/]*[@-~]))
|
||||
""",
|
||||
|
||||
@ -1,13 +1,33 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from functools import lru_cache
|
||||
from typing import Callable
|
||||
|
||||
from ._cell_widths import CELL_WIDTHS
|
||||
|
||||
# Regex to match sequence of the most common character ranges
|
||||
_is_single_cell_widths = re.compile("^[\u0020-\u006f\u00a0\u02ff\u0370-\u0482]*$").match
|
||||
# Ranges of unicode ordinals that produce a 1-cell wide character
|
||||
# This is non-exhaustive, but covers most common Western characters
|
||||
_SINGLE_CELL_UNICODE_RANGES: list[tuple[int, int]] = [
|
||||
(0x20, 0x7E), # Latin (excluding non-printable)
|
||||
(0xA0, 0xAC),
|
||||
(0xAE, 0x002FF),
|
||||
(0x00370, 0x00482), # Greek / Cyrillic
|
||||
(0x02500, 0x025FC), # Box drawing, box elements, geometric shapes
|
||||
(0x02800, 0x028FF), # Braille
|
||||
]
|
||||
|
||||
# A set of characters that are a single cell wide
|
||||
_SINGLE_CELLS = frozenset(
|
||||
[
|
||||
character
|
||||
for _start, _end in _SINGLE_CELL_UNICODE_RANGES
|
||||
for character in map(chr, range(_start, _end + 1))
|
||||
]
|
||||
)
|
||||
|
||||
# When called with a string this will return True if all
|
||||
# characters are single-cell, otherwise False
|
||||
_is_single_cell_widths: Callable[[str], bool] = _SINGLE_CELLS.issuperset
|
||||
|
||||
|
||||
@lru_cache(4096)
|
||||
@ -23,9 +43,9 @@ def cached_cell_len(text: str) -> int:
|
||||
Returns:
|
||||
int: Get the number of cells required to display text.
|
||||
"""
|
||||
_get_size = get_character_cell_size
|
||||
total_size = sum(_get_size(character) for character in text)
|
||||
return total_size
|
||||
if _is_single_cell_widths(text):
|
||||
return len(text)
|
||||
return sum(map(get_character_cell_size, text))
|
||||
|
||||
|
||||
def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> int:
|
||||
@ -39,9 +59,9 @@ def cell_len(text: str, _cell_len: Callable[[str], int] = cached_cell_len) -> in
|
||||
"""
|
||||
if len(text) < 512:
|
||||
return _cell_len(text)
|
||||
_get_size = get_character_cell_size
|
||||
total_size = sum(_get_size(character) for character in text)
|
||||
return total_size
|
||||
if _is_single_cell_widths(text):
|
||||
return len(text)
|
||||
return sum(map(get_character_cell_size, text))
|
||||
|
||||
|
||||
@lru_cache(maxsize=4096)
|
||||
@ -54,20 +74,7 @@ def get_character_cell_size(character: str) -> int:
|
||||
Returns:
|
||||
int: Number of cells (0, 1 or 2) occupied by that character.
|
||||
"""
|
||||
return _get_codepoint_cell_size(ord(character))
|
||||
|
||||
|
||||
@lru_cache(maxsize=4096)
|
||||
def _get_codepoint_cell_size(codepoint: int) -> int:
|
||||
"""Get the cell size of a character.
|
||||
|
||||
Args:
|
||||
codepoint (int): Codepoint of a character.
|
||||
|
||||
Returns:
|
||||
int: Number of cells (0, 1 or 2) occupied by that character.
|
||||
"""
|
||||
|
||||
codepoint = ord(character)
|
||||
_table = CELL_WIDTHS
|
||||
lower_bound = 0
|
||||
upper_bound = len(_table) - 1
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
from colorsys import rgb_to_hls
|
||||
from enum import IntEnum
|
||||
from functools import lru_cache
|
||||
@ -15,7 +15,7 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
from .text import Text
|
||||
|
||||
|
||||
WINDOWS = platform.system() == "Windows"
|
||||
WINDOWS = sys.platform == "win32"
|
||||
|
||||
|
||||
class ColorSystem(IntEnum):
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import inspect
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import threading
|
||||
import zlib
|
||||
@ -76,7 +75,7 @@ if TYPE_CHECKING:
|
||||
|
||||
JUPYTER_DEFAULT_COLUMNS = 115
|
||||
JUPYTER_DEFAULT_LINES = 100
|
||||
WINDOWS = platform.system() == "Windows"
|
||||
WINDOWS = sys.platform == "win32"
|
||||
|
||||
HighlighterType = Callable[[Union[str, "Text"]], "Text"]
|
||||
JustifyMethod = Literal["default", "left", "center", "right", "full"]
|
||||
@ -90,15 +89,15 @@ class NoChange:
|
||||
NO_CHANGE = NoChange()
|
||||
|
||||
try:
|
||||
_STDIN_FILENO = sys.__stdin__.fileno()
|
||||
_STDIN_FILENO = sys.__stdin__.fileno() # type: ignore[union-attr]
|
||||
except Exception:
|
||||
_STDIN_FILENO = 0
|
||||
try:
|
||||
_STDOUT_FILENO = sys.__stdout__.fileno()
|
||||
_STDOUT_FILENO = sys.__stdout__.fileno() # type: ignore[union-attr]
|
||||
except Exception:
|
||||
_STDOUT_FILENO = 1
|
||||
try:
|
||||
_STDERR_FILENO = sys.__stderr__.fileno()
|
||||
_STDERR_FILENO = sys.__stderr__.fileno() # type: ignore[union-attr]
|
||||
except Exception:
|
||||
_STDERR_FILENO = 2
|
||||
|
||||
@ -1006,19 +1005,14 @@ class Console:
|
||||
width: Optional[int] = None
|
||||
height: Optional[int] = None
|
||||
|
||||
if WINDOWS: # pragma: no cover
|
||||
streams = _STD_STREAMS_OUTPUT if WINDOWS else _STD_STREAMS
|
||||
for file_descriptor in streams:
|
||||
try:
|
||||
width, height = os.get_terminal_size()
|
||||
width, height = os.get_terminal_size(file_descriptor)
|
||||
except (AttributeError, ValueError, OSError): # Probably not a terminal
|
||||
pass
|
||||
else:
|
||||
for file_descriptor in _STD_STREAMS:
|
||||
try:
|
||||
width, height = os.get_terminal_size(file_descriptor)
|
||||
except (AttributeError, ValueError, OSError):
|
||||
pass
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
columns = self._environ.get("COLUMNS")
|
||||
if columns is not None and columns.isdigit():
|
||||
@ -1309,7 +1303,7 @@ class Console:
|
||||
|
||||
renderable = rich_cast(renderable)
|
||||
if hasattr(renderable, "__rich_console__") and not isclass(renderable):
|
||||
render_iterable = renderable.__rich_console__(self, _options) # type: ignore[union-attr]
|
||||
render_iterable = renderable.__rich_console__(self, _options)
|
||||
elif isinstance(renderable, str):
|
||||
text_renderable = self.render_str(
|
||||
renderable, highlight=_options.highlight, markup=_options.markup
|
||||
@ -1386,9 +1380,14 @@ class Console:
|
||||
extra_lines = render_options.height - len(lines)
|
||||
if extra_lines > 0:
|
||||
pad_line = [
|
||||
[Segment(" " * render_options.max_width, style), Segment("\n")]
|
||||
if new_lines
|
||||
else [Segment(" " * render_options.max_width, style)]
|
||||
(
|
||||
[
|
||||
Segment(" " * render_options.max_width, style),
|
||||
Segment("\n"),
|
||||
]
|
||||
if new_lines
|
||||
else [Segment(" " * render_options.max_width, style)]
|
||||
)
|
||||
]
|
||||
lines.extend(pad_line * extra_lines)
|
||||
|
||||
@ -1437,9 +1436,11 @@ class Console:
|
||||
rich_text.overflow = overflow
|
||||
else:
|
||||
rich_text = Text(
|
||||
_emoji_replace(text, default_variant=self._emoji_variant)
|
||||
if emoji_enabled
|
||||
else text,
|
||||
(
|
||||
_emoji_replace(text, default_variant=self._emoji_variant)
|
||||
if emoji_enabled
|
||||
else text
|
||||
),
|
||||
justify=justify,
|
||||
overflow=overflow,
|
||||
style=style,
|
||||
@ -1536,7 +1537,11 @@ class Console:
|
||||
if isinstance(renderable, str):
|
||||
append_text(
|
||||
self.render_str(
|
||||
renderable, emoji=emoji, markup=markup, highlighter=_highlighter
|
||||
renderable,
|
||||
emoji=emoji,
|
||||
markup=markup,
|
||||
highlight=highlight,
|
||||
highlighter=_highlighter,
|
||||
)
|
||||
)
|
||||
elif isinstance(renderable, Text):
|
||||
@ -1986,6 +1991,20 @@ class Console:
|
||||
):
|
||||
buffer_extend(line)
|
||||
|
||||
def on_broken_pipe(self) -> None:
|
||||
"""This function is called when a `BrokenPipeError` is raised.
|
||||
|
||||
This can occur when piping Textual output in Linux and macOS.
|
||||
The default implementation is to exit the app, but you could implement
|
||||
this method in a subclass to change the behavior.
|
||||
|
||||
See https://docs.python.org/3/library/signal.html#note-on-sigpipe for details.
|
||||
"""
|
||||
self.quiet = True
|
||||
devnull = os.open(os.devnull, os.O_WRONLY)
|
||||
os.dup2(devnull, sys.stdout.fileno())
|
||||
raise SystemExit(1)
|
||||
|
||||
def _check_buffer(self) -> None:
|
||||
"""Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False)
|
||||
Rendering is supported on Windows, Unix and Jupyter environments. For
|
||||
@ -1995,8 +2014,17 @@ class Console:
|
||||
if self.quiet:
|
||||
del self._buffer[:]
|
||||
return
|
||||
|
||||
try:
|
||||
self._write_buffer()
|
||||
except BrokenPipeError:
|
||||
self.on_broken_pipe()
|
||||
|
||||
def _write_buffer(self) -> None:
|
||||
"""Write the buffer to the output file."""
|
||||
|
||||
with self._lock:
|
||||
if self.record:
|
||||
if self.record and not self._buffer_index:
|
||||
with self._record_buffer_lock:
|
||||
self._record_buffer.extend(self._buffer[:])
|
||||
|
||||
@ -2166,7 +2194,7 @@ class Console:
|
||||
|
||||
"""
|
||||
text = self.export_text(clear=clear, styles=styles)
|
||||
with open(path, "wt", encoding="utf-8") as write_file:
|
||||
with open(path, "w", encoding="utf-8") as write_file:
|
||||
write_file.write(text)
|
||||
|
||||
def export_html(
|
||||
@ -2272,7 +2300,7 @@ class Console:
|
||||
code_format=code_format,
|
||||
inline_styles=inline_styles,
|
||||
)
|
||||
with open(path, "wt", encoding="utf-8") as write_file:
|
||||
with open(path, "w", encoding="utf-8") as write_file:
|
||||
write_file.write(html)
|
||||
|
||||
def export_svg(
|
||||
@ -2561,7 +2589,7 @@ class Console:
|
||||
font_aspect_ratio=font_aspect_ratio,
|
||||
unique_id=unique_id,
|
||||
)
|
||||
with open(path, "wt", encoding="utf-8") as write_file:
|
||||
with open(path, "w", encoding="utf-8") as write_file:
|
||||
write_file.write(svg)
|
||||
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ DEFAULT_STYLES: Dict[str, Style] = {
|
||||
"logging.level.notset": Style(dim=True),
|
||||
"logging.level.debug": Style(color="green"),
|
||||
"logging.level.info": Style(color="blue"),
|
||||
"logging.level.warning": Style(color="red"),
|
||||
"logging.level.warning": Style(color="yellow"),
|
||||
"logging.level.error": Style(color="red", bold=True),
|
||||
"logging.level.critical": Style(color="red", bold=True, reverse=True),
|
||||
"log.level": Style.null(),
|
||||
@ -120,6 +120,7 @@ DEFAULT_STYLES: Dict[str, Style] = {
|
||||
"traceback.exc_type": Style(color="bright_red", bold=True),
|
||||
"traceback.exc_value": Style.null(),
|
||||
"traceback.offset": Style(color="bright_red", bold=True),
|
||||
"traceback.error_range": Style(underline=True, bold=True, dim=False),
|
||||
"bar.back": Style(color="grey23"),
|
||||
"bar.complete": Style(color="rgb(249,38,114)"),
|
||||
"bar.finished": Style(color="rgb(114,156,31)"),
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
# coding: utf-8
|
||||
"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2
|
||||
|
||||
The functions declared in this module should cover the different
|
||||
@ -27,7 +26,7 @@ def _to_str(
|
||||
if size == 1:
|
||||
return "1 byte"
|
||||
elif size < base:
|
||||
return "{:,} bytes".format(size)
|
||||
return f"{size:,} bytes"
|
||||
|
||||
for i, suffix in enumerate(suffixes, 2): # noqa: B007
|
||||
unit = base**i
|
||||
|
||||
@ -98,7 +98,7 @@ class ReprHighlighter(RegexHighlighter):
|
||||
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
|
||||
r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
|
||||
r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
|
||||
r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~]*)",
|
||||
r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ class Live(JupyterMixin, RenderHook):
|
||||
|
||||
Args:
|
||||
renderable (RenderableType, optional): The renderable to live display. Defaults to displaying nothing.
|
||||
console (Console, optional): Optional Console instance. Default will an internal Console instance writing to stdout.
|
||||
console (Console, optional): Optional Console instance. Defaults to an internal Console instance writing to stdout.
|
||||
screen (bool, optional): Enable alternate screen mode. Defaults to False.
|
||||
auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()` or `update()` with refresh flag. Defaults to True
|
||||
refresh_per_second (float, optional): Number of times per second to refresh the live display. Defaults to 4.
|
||||
|
||||
@ -36,11 +36,13 @@ class RichHandler(Handler):
|
||||
markup (bool, optional): Enable console markup in log messages. Defaults to False.
|
||||
rich_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False.
|
||||
tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks, or None for full width. Defaults to None.
|
||||
tracebacks_code_width (int, optional): Number of code characters used to render tracebacks, or None for full width. Defaults to 88.
|
||||
tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks, or None for full width. Defaults to None.
|
||||
tracebacks_theme (str, optional): Override pygments theme used in traceback.
|
||||
tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to True.
|
||||
tracebacks_show_locals (bool, optional): Enable display of locals in tracebacks. Defaults to False.
|
||||
tracebacks_suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
|
||||
tracebacks_max_frames (int, optional): Optional maximum number of frames returned by traceback.
|
||||
locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.
|
||||
Defaults to 10.
|
||||
locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.
|
||||
@ -74,11 +76,13 @@ class RichHandler(Handler):
|
||||
markup: bool = False,
|
||||
rich_tracebacks: bool = False,
|
||||
tracebacks_width: Optional[int] = None,
|
||||
tracebacks_code_width: int = 88,
|
||||
tracebacks_extra_lines: int = 3,
|
||||
tracebacks_theme: Optional[str] = None,
|
||||
tracebacks_word_wrap: bool = True,
|
||||
tracebacks_show_locals: bool = False,
|
||||
tracebacks_suppress: Iterable[Union[str, ModuleType]] = (),
|
||||
tracebacks_max_frames: int = 100,
|
||||
locals_max_length: int = 10,
|
||||
locals_max_string: int = 80,
|
||||
log_time_format: Union[str, FormatTimeCallable] = "[%x %X]",
|
||||
@ -104,6 +108,8 @@ class RichHandler(Handler):
|
||||
self.tracebacks_word_wrap = tracebacks_word_wrap
|
||||
self.tracebacks_show_locals = tracebacks_show_locals
|
||||
self.tracebacks_suppress = tracebacks_suppress
|
||||
self.tracebacks_max_frames = tracebacks_max_frames
|
||||
self.tracebacks_code_width = tracebacks_code_width
|
||||
self.locals_max_length = locals_max_length
|
||||
self.locals_max_string = locals_max_string
|
||||
self.keywords = keywords
|
||||
@ -140,6 +146,7 @@ class RichHandler(Handler):
|
||||
exc_value,
|
||||
exc_traceback,
|
||||
width=self.tracebacks_width,
|
||||
code_width=self.tracebacks_code_width,
|
||||
extra_lines=self.tracebacks_extra_lines,
|
||||
theme=self.tracebacks_theme,
|
||||
word_wrap=self.tracebacks_word_wrap,
|
||||
@ -147,6 +154,7 @@ class RichHandler(Handler):
|
||||
locals_max_length=self.locals_max_length,
|
||||
locals_max_string=self.locals_max_string,
|
||||
suppress=self.tracebacks_suppress,
|
||||
max_frames=self.tracebacks_max_frames,
|
||||
)
|
||||
message = record.getMessage()
|
||||
if self.formatter:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from typing import cast, List, Optional, Tuple, TYPE_CHECKING, Union
|
||||
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .console import (
|
||||
@ -7,11 +7,11 @@ if TYPE_CHECKING:
|
||||
RenderableType,
|
||||
RenderResult,
|
||||
)
|
||||
|
||||
from .jupyter import JupyterMixin
|
||||
from .measure import Measurement
|
||||
from .style import Style
|
||||
from .segment import Segment
|
||||
|
||||
from .style import Style
|
||||
|
||||
PaddingDimensions = Union[int, Tuple[int], Tuple[int, int], Tuple[int, int, int, int]]
|
||||
|
||||
@ -66,10 +66,10 @@ class Padding(JupyterMixin):
|
||||
_pad = pad[0]
|
||||
return (_pad, _pad, _pad, _pad)
|
||||
if len(pad) == 2:
|
||||
pad_top, pad_right = cast(Tuple[int, int], pad)
|
||||
pad_top, pad_right = pad
|
||||
return (pad_top, pad_right, pad_top, pad_right)
|
||||
if len(pad) == 4:
|
||||
top, right, bottom, left = cast(Tuple[int, int, int, int], pad)
|
||||
top, right, bottom, left = pad
|
||||
return (top, right, bottom, left)
|
||||
raise ValueError(f"1, 2 or 4 integers required for padding; {len(pad)} given")
|
||||
|
||||
|
||||
@ -22,11 +22,13 @@ class Panel(JupyterMixin):
|
||||
|
||||
Args:
|
||||
renderable (RenderableType): A console renderable object.
|
||||
box (Box, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`.
|
||||
Defaults to box.ROUNDED.
|
||||
box (Box, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`. Defaults to box.ROUNDED.
|
||||
title (Optional[TextType], optional): Optional title displayed in panel header. Defaults to None.
|
||||
title_align (AlignMethod, optional): Alignment of title. Defaults to "center".
|
||||
subtitle (Optional[TextType], optional): Optional subtitle displayed in panel footer. Defaults to None.
|
||||
subtitle_align (AlignMethod, optional): Alignment of subtitle. Defaults to "center".
|
||||
safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.
|
||||
expand (bool, optional): If True the panel will stretch to fill the console
|
||||
width, otherwise it will be sized to fit the contents. Defaults to True.
|
||||
expand (bool, optional): If True the panel will stretch to fill the console width, otherwise it will be sized to fit the contents. Defaults to True.
|
||||
style (str, optional): The style of the panel (border and contents). Defaults to "none".
|
||||
border_style (str, optional): The style of the border. Defaults to "none".
|
||||
width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.
|
||||
@ -144,7 +146,8 @@ class Panel(JupyterMixin):
|
||||
Padding(self.renderable, _padding) if any(_padding) else self.renderable
|
||||
)
|
||||
style = console.get_style(self.style)
|
||||
border_style = style + console.get_style(self.border_style)
|
||||
partial_border_style = console.get_style(self.border_style)
|
||||
border_style = style + partial_border_style
|
||||
width = (
|
||||
options.max_width
|
||||
if self.width is None
|
||||
@ -172,6 +175,9 @@ class Panel(JupyterMixin):
|
||||
text = text.copy()
|
||||
text.truncate(width)
|
||||
excess_space = width - cell_len(text.plain)
|
||||
if text.style:
|
||||
text.stylize(console.get_style(text.style))
|
||||
|
||||
if excess_space:
|
||||
if align == "left":
|
||||
return Text.assemble(
|
||||
@ -200,7 +206,7 @@ class Panel(JupyterMixin):
|
||||
|
||||
title_text = self._title
|
||||
if title_text is not None:
|
||||
title_text.stylize_before(border_style)
|
||||
title_text.stylize_before(partial_border_style)
|
||||
|
||||
child_width = (
|
||||
width - 2
|
||||
@ -249,7 +255,7 @@ class Panel(JupyterMixin):
|
||||
|
||||
subtitle_text = self._subtitle
|
||||
if subtitle_text is not None:
|
||||
subtitle_text.stylize_before(border_style)
|
||||
subtitle_text.stylize_before(partial_border_style)
|
||||
|
||||
if subtitle_text is None or width <= 4:
|
||||
yield Segment(box.get_bottom([width - 2]), border_style)
|
||||
|
||||
@ -3,6 +3,7 @@ import collections
|
||||
import dataclasses
|
||||
import inspect
|
||||
import os
|
||||
import reprlib
|
||||
import sys
|
||||
from array import array
|
||||
from collections import Counter, UserDict, UserList, defaultdict, deque
|
||||
@ -15,6 +16,7 @@ from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
DefaultDict,
|
||||
Deque,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
@ -77,7 +79,10 @@ def _is_dataclass_repr(obj: object) -> bool:
|
||||
# Digging in to a lot of internals here
|
||||
# Catching all exceptions in case something is missing on a non CPython implementation
|
||||
try:
|
||||
return obj.__repr__.__code__.co_filename == dataclasses.__file__
|
||||
return obj.__repr__.__code__.co_filename in (
|
||||
dataclasses.__file__,
|
||||
reprlib.__file__,
|
||||
)
|
||||
except Exception: # pragma: no coverage
|
||||
return False
|
||||
|
||||
@ -130,17 +135,19 @@ def _ipy_display_hook(
|
||||
if _safe_isinstance(value, ConsoleRenderable):
|
||||
console.line()
|
||||
console.print(
|
||||
value
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
indent_guides=indent_guides,
|
||||
max_length=max_length,
|
||||
max_string=max_string,
|
||||
max_depth=max_depth,
|
||||
expand_all=expand_all,
|
||||
margin=12,
|
||||
(
|
||||
value
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
indent_guides=indent_guides,
|
||||
max_length=max_length,
|
||||
max_string=max_string,
|
||||
max_depth=max_depth,
|
||||
expand_all=expand_all,
|
||||
margin=12,
|
||||
)
|
||||
),
|
||||
crop=crop,
|
||||
new_line_start=True,
|
||||
@ -196,16 +203,18 @@ def install(
|
||||
assert console is not None
|
||||
builtins._ = None # type: ignore[attr-defined]
|
||||
console.print(
|
||||
value
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
indent_guides=indent_guides,
|
||||
max_length=max_length,
|
||||
max_string=max_string,
|
||||
max_depth=max_depth,
|
||||
expand_all=expand_all,
|
||||
(
|
||||
value
|
||||
if _safe_isinstance(value, RichRenderable)
|
||||
else Pretty(
|
||||
value,
|
||||
overflow=overflow,
|
||||
indent_guides=indent_guides,
|
||||
max_length=max_length,
|
||||
max_string=max_string,
|
||||
max_depth=max_depth,
|
||||
expand_all=expand_all,
|
||||
)
|
||||
),
|
||||
crop=crop,
|
||||
)
|
||||
@ -353,6 +362,16 @@ def _get_braces_for_defaultdict(_object: DefaultDict[Any, Any]) -> Tuple[str, st
|
||||
)
|
||||
|
||||
|
||||
def _get_braces_for_deque(_object: Deque[Any]) -> Tuple[str, str, str]:
|
||||
if _object.maxlen is None:
|
||||
return ("deque([", "])", "deque()")
|
||||
return (
|
||||
"deque([",
|
||||
f"], maxlen={_object.maxlen})",
|
||||
f"deque(maxlen={_object.maxlen})",
|
||||
)
|
||||
|
||||
|
||||
def _get_braces_for_array(_object: "array[Any]") -> Tuple[str, str, str]:
|
||||
return (f"array({_object.typecode!r}, [", "])", f"array({_object.typecode!r})")
|
||||
|
||||
@ -362,7 +381,7 @@ _BRACES: Dict[type, Callable[[Any], Tuple[str, str, str]]] = {
|
||||
array: _get_braces_for_array,
|
||||
defaultdict: _get_braces_for_defaultdict,
|
||||
Counter: lambda _object: ("Counter({", "})", "Counter()"),
|
||||
deque: lambda _object: ("deque([", "])", "deque()"),
|
||||
deque: _get_braces_for_deque,
|
||||
dict: lambda _object: ("{", "}", "{}"),
|
||||
UserDict: lambda _object: ("{", "}", "{}"),
|
||||
frozenset: lambda _object: ("frozenset({", "})", "frozenset()"),
|
||||
@ -762,7 +781,9 @@ def traverse(
|
||||
)
|
||||
|
||||
for last, field in loop_last(
|
||||
field for field in fields(obj) if field.repr
|
||||
field
|
||||
for field in fields(obj)
|
||||
if field.repr and hasattr(obj, field.name)
|
||||
):
|
||||
child_node = _traverse(getattr(obj, field.name), depth=depth + 1)
|
||||
child_node.key_repr = field.name
|
||||
@ -846,7 +867,7 @@ def traverse(
|
||||
pop_visited(obj_id)
|
||||
else:
|
||||
node = Node(value_repr=to_repr(obj), last=root)
|
||||
node.is_tuple = _safe_isinstance(obj, tuple)
|
||||
node.is_tuple = type(obj) == tuple
|
||||
node.is_namedtuple = _is_namedtuple(obj)
|
||||
return node
|
||||
|
||||
|
||||
@ -39,6 +39,11 @@ if sys.version_info >= (3, 8):
|
||||
else:
|
||||
from pip._vendor.typing_extensions import Literal # pragma: no cover
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
from typing import Self
|
||||
else:
|
||||
from pip._vendor.typing_extensions import Self # pragma: no cover
|
||||
|
||||
from . import filesize, get_console
|
||||
from .console import Console, Group, JustifyMethod, RenderableType
|
||||
from .highlighter import Highlighter
|
||||
@ -70,7 +75,7 @@ class _TrackThread(Thread):
|
||||
self.done = Event()
|
||||
|
||||
self.completed = 0
|
||||
super().__init__()
|
||||
super().__init__(daemon=True)
|
||||
|
||||
def run(self) -> None:
|
||||
task_id = self.task_id
|
||||
@ -78,7 +83,7 @@ class _TrackThread(Thread):
|
||||
update_period = self.update_period
|
||||
last_completed = 0
|
||||
wait = self.done.wait
|
||||
while not wait(update_period):
|
||||
while not wait(update_period) and self.progress.live.is_started:
|
||||
completed = self.completed
|
||||
if last_completed != completed:
|
||||
advance(task_id, completed - last_completed)
|
||||
@ -104,6 +109,7 @@ def track(
|
||||
sequence: Union[Sequence[ProgressType], Iterable[ProgressType]],
|
||||
description: str = "Working...",
|
||||
total: Optional[float] = None,
|
||||
completed: int = 0,
|
||||
auto_refresh: bool = True,
|
||||
console: Optional[Console] = None,
|
||||
transient: bool = False,
|
||||
@ -123,6 +129,7 @@ def track(
|
||||
sequence (Iterable[ProgressType]): A sequence (must support "len") you wish to iterate over.
|
||||
description (str, optional): Description of task show next to progress bar. Defaults to "Working".
|
||||
total: (float, optional): Total number of steps. Default is len(sequence).
|
||||
completed (int, optional): Number of steps completed so far. Defaults to 0.
|
||||
auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True.
|
||||
transient: (bool, optional): Clear the progress on exit. Defaults to False.
|
||||
console (Console, optional): Console to write to. Default creates internal Console instance.
|
||||
@ -166,7 +173,11 @@ def track(
|
||||
|
||||
with progress:
|
||||
yield from progress.track(
|
||||
sequence, total=total, description=description, update_period=update_period
|
||||
sequence,
|
||||
total=total,
|
||||
completed=completed,
|
||||
description=description,
|
||||
update_period=update_period,
|
||||
)
|
||||
|
||||
|
||||
@ -269,6 +280,9 @@ class _Reader(RawIOBase, BinaryIO):
|
||||
def write(self, s: Any) -> int:
|
||||
raise UnsupportedOperation("write")
|
||||
|
||||
def writelines(self, lines: Iterable[Any]) -> None:
|
||||
raise UnsupportedOperation("writelines")
|
||||
|
||||
|
||||
class _ReadContext(ContextManager[_I], Generic[_I]):
|
||||
"""A utility class to handle a context for both a reader and a progress."""
|
||||
@ -1050,7 +1064,7 @@ class Progress(JupyterMixin):
|
||||
"""Renders an auto-updating progress bar(s).
|
||||
|
||||
Args:
|
||||
console (Console, optional): Optional Console instance. Default will an internal Console instance writing to stdout.
|
||||
console (Console, optional): Optional Console instance. Defaults to an internal Console instance writing to stdout.
|
||||
auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()`.
|
||||
refresh_per_second (Optional[float], optional): Number of times per second to refresh the progress information or None to use default (10). Defaults to None.
|
||||
speed_estimate_period: (float, optional): Period (in seconds) used to calculate the speed estimate. Defaults to 30.
|
||||
@ -1161,10 +1175,10 @@ class Progress(JupyterMixin):
|
||||
def stop(self) -> None:
|
||||
"""Stop the progress display."""
|
||||
self.live.stop()
|
||||
if not self.console.is_interactive:
|
||||
if not self.console.is_interactive and not self.console.is_jupyter:
|
||||
self.console.print()
|
||||
|
||||
def __enter__(self) -> "Progress":
|
||||
def __enter__(self) -> Self:
|
||||
self.start()
|
||||
return self
|
||||
|
||||
@ -1180,6 +1194,7 @@ class Progress(JupyterMixin):
|
||||
self,
|
||||
sequence: Union[Iterable[ProgressType], Sequence[ProgressType]],
|
||||
total: Optional[float] = None,
|
||||
completed: int = 0,
|
||||
task_id: Optional[TaskID] = None,
|
||||
description: str = "Working...",
|
||||
update_period: float = 0.1,
|
||||
@ -1189,6 +1204,7 @@ class Progress(JupyterMixin):
|
||||
Args:
|
||||
sequence (Sequence[ProgressType]): A sequence of values you want to iterate over and track progress.
|
||||
total: (float, optional): Total number of steps. Default is len(sequence).
|
||||
completed (int, optional): Number of steps completed so far. Defaults to 0.
|
||||
task_id: (TaskID): Task to track. Default is new task.
|
||||
description: (str, optional): Description of task, if new task is created.
|
||||
update_period (float, optional): Minimum time (in seconds) between calls to update(). Defaults to 0.1.
|
||||
@ -1200,9 +1216,9 @@ class Progress(JupyterMixin):
|
||||
total = float(length_hint(sequence)) or None
|
||||
|
||||
if task_id is None:
|
||||
task_id = self.add_task(description, total=total)
|
||||
task_id = self.add_task(description, total=total, completed=completed)
|
||||
else:
|
||||
self.update(task_id, total=total)
|
||||
self.update(task_id, total=total, completed=completed)
|
||||
|
||||
if self.live.auto_refresh:
|
||||
with _TrackThread(self, task_id, update_period) as track_thread:
|
||||
@ -1326,7 +1342,7 @@ class Progress(JupyterMixin):
|
||||
# normalize the mode (always rb, rt)
|
||||
_mode = "".join(sorted(mode, reverse=False))
|
||||
if _mode not in ("br", "rt", "r"):
|
||||
raise ValueError("invalid mode {!r}".format(mode))
|
||||
raise ValueError(f"invalid mode {mode!r}")
|
||||
|
||||
# patch buffering to provide the same behaviour as the builtin `open`
|
||||
line_buffering = buffering == 1
|
||||
|
||||
@ -108,7 +108,7 @@ class ProgressBar(JupyterMixin):
|
||||
|
||||
for index in range(PULSE_SIZE):
|
||||
position = index / PULSE_SIZE
|
||||
fade = 0.5 + cos((position * pi * 2)) / 2.0
|
||||
fade = 0.5 + cos(position * pi * 2) / 2.0
|
||||
color = blend_rgb(fore_color, back_color, cross_fade=fade)
|
||||
append(_Segment(bar, _Style(color=from_triplet(color))))
|
||||
return segments
|
||||
|
||||
@ -36,6 +36,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console (Console, optional): A Console instance or None to use global console. Defaults to None.
|
||||
password (bool, optional): Enable password input. Defaults to False.
|
||||
choices (List[str], optional): A list of valid choices. Defaults to None.
|
||||
case_sensitive (bool, optional): Matching of choices should be case-sensitive. Defaults to True.
|
||||
show_default (bool, optional): Show default in prompt. Defaults to True.
|
||||
show_choices (bool, optional): Show choices in prompt. Defaults to True.
|
||||
"""
|
||||
@ -57,6 +58,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console: Optional[Console] = None,
|
||||
password: bool = False,
|
||||
choices: Optional[List[str]] = None,
|
||||
case_sensitive: bool = True,
|
||||
show_default: bool = True,
|
||||
show_choices: bool = True,
|
||||
) -> None:
|
||||
@ -69,6 +71,7 @@ class PromptBase(Generic[PromptType]):
|
||||
self.password = password
|
||||
if choices is not None:
|
||||
self.choices = choices
|
||||
self.case_sensitive = case_sensitive
|
||||
self.show_default = show_default
|
||||
self.show_choices = show_choices
|
||||
|
||||
@ -81,6 +84,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console: Optional[Console] = None,
|
||||
password: bool = False,
|
||||
choices: Optional[List[str]] = None,
|
||||
case_sensitive: bool = True,
|
||||
show_default: bool = True,
|
||||
show_choices: bool = True,
|
||||
default: DefaultType,
|
||||
@ -97,6 +101,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console: Optional[Console] = None,
|
||||
password: bool = False,
|
||||
choices: Optional[List[str]] = None,
|
||||
case_sensitive: bool = True,
|
||||
show_default: bool = True,
|
||||
show_choices: bool = True,
|
||||
stream: Optional[TextIO] = None,
|
||||
@ -111,6 +116,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console: Optional[Console] = None,
|
||||
password: bool = False,
|
||||
choices: Optional[List[str]] = None,
|
||||
case_sensitive: bool = True,
|
||||
show_default: bool = True,
|
||||
show_choices: bool = True,
|
||||
default: Any = ...,
|
||||
@ -126,6 +132,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console (Console, optional): A Console instance or None to use global console. Defaults to None.
|
||||
password (bool, optional): Enable password input. Defaults to False.
|
||||
choices (List[str], optional): A list of valid choices. Defaults to None.
|
||||
case_sensitive (bool, optional): Matching of choices should be case-sensitive. Defaults to True.
|
||||
show_default (bool, optional): Show default in prompt. Defaults to True.
|
||||
show_choices (bool, optional): Show choices in prompt. Defaults to True.
|
||||
stream (TextIO, optional): Optional text file open for reading to get input. Defaults to None.
|
||||
@ -135,6 +142,7 @@ class PromptBase(Generic[PromptType]):
|
||||
console=console,
|
||||
password=password,
|
||||
choices=choices,
|
||||
case_sensitive=case_sensitive,
|
||||
show_default=show_default,
|
||||
show_choices=show_choices,
|
||||
)
|
||||
@ -212,7 +220,9 @@ class PromptBase(Generic[PromptType]):
|
||||
bool: True if choice was valid, otherwise False.
|
||||
"""
|
||||
assert self.choices is not None
|
||||
return value.strip() in self.choices
|
||||
if self.case_sensitive:
|
||||
return value.strip() in self.choices
|
||||
return value.strip().lower() in [choice.lower() for choice in self.choices]
|
||||
|
||||
def process_response(self, value: str) -> PromptType:
|
||||
"""Process response from user, convert to prompt type.
|
||||
@ -232,9 +242,17 @@ class PromptBase(Generic[PromptType]):
|
||||
except ValueError:
|
||||
raise InvalidResponse(self.validate_error_message)
|
||||
|
||||
if self.choices is not None and not self.check_choice(value):
|
||||
raise InvalidResponse(self.illegal_choice_message)
|
||||
if self.choices is not None:
|
||||
if not self.check_choice(value):
|
||||
raise InvalidResponse(self.illegal_choice_message)
|
||||
|
||||
if not self.case_sensitive:
|
||||
# return the original choice, not the lower case version
|
||||
return_value = self.response_type(
|
||||
self.choices[
|
||||
[choice.lower() for choice in self.choices].index(value.lower())
|
||||
]
|
||||
)
|
||||
return return_value
|
||||
|
||||
def on_validate_error(self, value: str, error: InvalidResponse) -> None:
|
||||
@ -371,5 +389,12 @@ if __name__ == "__main__": # pragma: no cover
|
||||
fruit = Prompt.ask("Enter a fruit", choices=["apple", "orange", "pear"])
|
||||
print(f"fruit={fruit!r}")
|
||||
|
||||
doggie = Prompt.ask(
|
||||
"What's the best Dog? (Case INSENSITIVE)",
|
||||
choices=["Border Terrier", "Collie", "Labradoodle"],
|
||||
case_sensitive=False,
|
||||
)
|
||||
print(f"doggie={doggie!r}")
|
||||
|
||||
else:
|
||||
print("[b]OK :loudly_crying_face:")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user