Coverage for sources/mimeogram/__/distribution.py: 95%
34 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-17 22:34 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-17 22:34 +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 # TODO: Python 3.12: importlib.metadata
49 from importlib_metadata import packages_distributions
50 # https://github.com/pypa/packaging-problems/issues/609
51 name = packages_distributions( ).get( package )
52 if name is None: # Development sources rather than distribution.
53 editable = True # Implies no use of importlib.resources.
54 location, name = (
55 await _acquire_development_information(
56 location = project_anchor ) )
57 else:
58 editable = False
59 name = name[ 0 ]
60 location = await _acquire_production_location( package, exits )
61 return selfclass(
62 editable = editable, location = location, name = name )
64 def provide_data_location( self, *appendages: str ) -> __.Path:
65 ''' Provides location of distribution data. '''
66 base = self.location / 'data'
67 if appendages: return base.joinpath( *appendages )
68 return base
71async def _acquire_development_information(
72 location: __.Absential[ __.Path ] = __.absent
73) -> tuple[ __.Path, str ]:
74 from tomli import loads
75 if __.is_absent( location ):
76 location = __.Path( __file__ ).parents[ 3 ].resolve( strict = True )
77 pyproject = await _io.acquire_text_file_async(
78 location / 'pyproject.toml', deserializer = loads )
79 name = pyproject[ 'project' ][ 'name' ]
80 return location, name
83async def _acquire_production_location(
84 package: str, exits: __.ExitsAsync
85) -> __.Path:
86 # TODO: Python 3.12: importlib.resources
87 # TODO: 'importlib_resources' PR to fix 'as_file' type signature.
88 from importlib_resources import files, as_file # pyright: ignore
89 # Extract package contents to temporary directory, if necessary.
90 return exits.enter_context(
91 as_file( files( package ) ) ) # pyright: ignore