Coverage for sources/mimeogram/__/distribution.py: 95%
34 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-16 03:28 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-16 03:28 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Information about package distribution. '''
24from . import imports as __
25from . import io as _io
28class Information(
29 metaclass = __.ImmutableStandardDataclass,
30 decorators = ( __.standard_dataclass, ),
31):
32 ''' Information about a package distribution. '''
34 name: str
35 location: __.Path
36 editable: bool
38 @classmethod
39 async def prepare(
40 selfclass, package: str, exits: __.ExitsAsync,
41 project_anchor: __.Absential[ __.Path ] = __.absent,
42 ) -> __.typx.Self:
43 ''' Acquires information about our package distribution. '''
44 import sys
45 # Detect PyInstaller bundle.
46 if getattr( sys, 'frozen', False ) and hasattr( sys, '_MEIPASS' ): 46 ↛ 47line 46 didn't jump to line 47 because the condition on line 46 was never true
47 project_anchor = __.Path( getattr( sys, '_MEIPASS' ) )
48 from importlib.metadata import packages_distributions
49 # https://github.com/pypa/packaging-problems/issues/609
50 name = packages_distributions( ).get( package )
51 if name is None: # Development sources rather than distribution.
52 editable = True # Implies no use of importlib.resources.
53 location, name = (
54 await _acquire_development_information(
55 location = project_anchor ) )
56 else:
57 editable = False
58 name = name[ 0 ]
59 location = await _acquire_production_location( package, exits )
60 return selfclass(
61 editable = editable, location = location, name = name )
63 def provide_data_location( self, *appendages: str ) -> __.Path:
64 ''' Provides location of distribution data. '''
65 base = self.location / 'data'
66 if appendages: return base.joinpath( *appendages )
67 return base
70async def _acquire_development_information(
71 location: __.Absential[ __.Path ] = __.absent
72) -> tuple[ __.Path, str ]:
73 from tomli import loads
74 if __.is_absent( location ):
75 location = __.Path( __file__ ).parents[ 3 ].resolve( strict = True )
76 pyproject = await _io.acquire_text_file_async(
77 location / 'pyproject.toml', deserializer = loads )
78 name = pyproject[ 'project' ][ 'name' ]
79 return location, name
82async def _acquire_production_location(
83 package: str, exits: __.ExitsAsync
84) -> __.Path:
85 # TODO: Python 3.12: importlib.resources
86 # TODO: 'importlib_resources' PR to fix 'as_file' type signature.
87 from importlib_resources import files, as_file # pyright: ignore
88 # Extract package contents to temporary directory, if necessary.
89 return exits.enter_context(
90 as_file( files( package ) ) ) # pyright: ignore