resolve name conflicts rather than just giving up
this lets us merge libraries without having to mutate `other`, which brings a bunch of problems around cache invalidation
This commit is contained in:
		
							parent
							
								
									566ba99f9c
								
							
						
					
					
						commit
						2e5d51b0af
					
				@ -88,7 +88,12 @@ class DeviceLibrary:
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        self.generators[const.pattern.name] = lambda: const
 | 
					        self.generators[const.pattern.name] = lambda: const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add(self: L, other: L) -> L:
 | 
					    def add(
 | 
				
			||||||
 | 
					            self: D,
 | 
				
			||||||
 | 
					            other: D,
 | 
				
			||||||
 | 
					            use_ours: Callable[[str], bool] = lambda name: False,
 | 
				
			||||||
 | 
					            use_theirs: Callable[[str], bool] = lambda name: False,
 | 
				
			||||||
 | 
					            ) -> D:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Add keys from another library into this one.
 | 
					        Add keys from another library into this one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -96,15 +101,25 @@ class DeviceLibrary:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            other: The library to insert keys from
 | 
					            other: The library to insert keys from
 | 
				
			||||||
 | 
					            use_ours: Decision function for name conflicts. Will be called with duplicate cell names.
 | 
				
			||||||
 | 
					                Should return `True` if the value from `self` should be used.
 | 
				
			||||||
 | 
					            use_theirs: Decision function for name conflicts. Same format as `use_ours`.
 | 
				
			||||||
 | 
					                Should return `True` if the value from `other` should be used.
 | 
				
			||||||
 | 
					                `use_ours` takes priority over `use_theirs`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Returns:
 | 
					        Returns:
 | 
				
			||||||
            self
 | 
					            self
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        conflicts = [key for key in other.generators
 | 
					        duplicates = set(self.keys()) & set(other.keys())
 | 
				
			||||||
                     if key in self.generators]
 | 
					        keep_ours = set(name for name in duplicates if use_ours(name))
 | 
				
			||||||
 | 
					        keep_theirs = set(name for name in duplicates - keep_ours if use_theirs(name))
 | 
				
			||||||
 | 
					        conflicts = duplicates - keep_ours - keep_theirs
 | 
				
			||||||
        if conflicts:
 | 
					        if conflicts:
 | 
				
			||||||
            raise LibraryError('Duplicate keys encountered in library merge: ' + pformat(conflicts))
 | 
					            raise DeviceLibraryError('Duplicate keys encountered in DeviceLibrary merge: '
 | 
				
			||||||
 | 
					                                     + pformat(conflicts))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.generators.update(other.generators)
 | 
					        for name in set(other.generators.keys()) - keep_ours:
 | 
				
			||||||
        self.cache.update(other.cache)
 | 
					            self.generators[name] = other.generators[name]
 | 
				
			||||||
 | 
					            if name in other.cache:
 | 
				
			||||||
 | 
					                self.cache[name] = other.cache[name]
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
				
			|||||||
@ -205,31 +205,52 @@ class Library:
 | 
				
			|||||||
            _ = self.get_secondary(*key2)
 | 
					            _ = self.get_secondary(*key2)
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def add(self: L, other: L) -> L:
 | 
					    def add(
 | 
				
			||||||
 | 
					            self: L,
 | 
				
			||||||
 | 
					            other: L,
 | 
				
			||||||
 | 
					            use_ours: Callable[[Union[str, Tuple[str, str]]], bool] = lambda name: False,
 | 
				
			||||||
 | 
					            use_theirs: Callable[[Union[str, Tuple[str, str]]], bool] = lambda name: False,
 | 
				
			||||||
 | 
					            ) -> L:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Add keys from another library into this one.
 | 
					        Add keys from another library into this one.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        There must be no conflicting keys.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            other: The library to insert keys from
 | 
					            other: The library to insert keys from
 | 
				
			||||||
 | 
					            use_ours: Decision function for name conflicts.
 | 
				
			||||||
 | 
					                May be called with cell names and (name, tag) tuples for primary or
 | 
				
			||||||
 | 
					                secondary cells, respectively.
 | 
				
			||||||
 | 
					                Should return `True` if the value from `self` should be used.
 | 
				
			||||||
 | 
					            use_theirs: Decision function for name conflicts. Same format as `use_ours`.
 | 
				
			||||||
 | 
					                Should return `True` if the value from `other` should be used.
 | 
				
			||||||
 | 
					                `use_ours` takes priority over `use_theirs`.
 | 
				
			||||||
        Returns:
 | 
					        Returns:
 | 
				
			||||||
            self
 | 
					            self
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        conflicts = [key for key in other.primary
 | 
					        duplicates1 = set(self.primary.keys()) & set(other.primary.keys())
 | 
				
			||||||
                     if key in self.primary]
 | 
					        duplicates2 = set(self.secondary.keys()) & set(other.secondary.keys())
 | 
				
			||||||
        if conflicts:
 | 
					        keep_ours1 = set(name for name in duplicates1 if use_ours(name))
 | 
				
			||||||
            raise LibraryError('Duplicate keys encountered in library merge: ' + pformat(conflicts))
 | 
					        keep_ours2 = set(name for name in duplicates2 if use_ours(name))
 | 
				
			||||||
 | 
					        keep_theirs1 = set(name for name in duplicates1 - keep_ours1 if use_theirs(name))
 | 
				
			||||||
 | 
					        keep_theirs2 = set(name for name in duplicates2 - keep_ours2 if use_theirs(name))
 | 
				
			||||||
 | 
					        conflicts1 = duplicates1 - keep_ours1 - keep_theirs1
 | 
				
			||||||
 | 
					        conflicts2 = duplicates2 - keep_ours2 - keep_theirs2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if conflicts1:
 | 
				
			||||||
 | 
					            raise LibraryError('Unresolved duplicate keys encountered in library merge: ' + pformat(conflicts1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        conflicts2 = [key2 for key2 in other.secondary
 | 
					 | 
				
			||||||
                      if key2 in self.secondary]
 | 
					 | 
				
			||||||
        if conflicts2:
 | 
					        if conflicts2:
 | 
				
			||||||
            raise LibraryError('Duplicate secondary keys encountered in library merge: ' + pformat(conflicts2))
 | 
					            raise LibraryError('Unresolved duplicate secondary keys encountered in library merge: ' + pformat(conflicts2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for key1 in set(other.primary.keys()) - keep_ours1:
 | 
				
			||||||
 | 
					            self[key1] = other.primary[key1]
 | 
				
			||||||
 | 
					            if key1 in other.cache:
 | 
				
			||||||
 | 
					                self.cache[key1] = other.cache[key1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for key2 in set(other.secondary.keys()) - keep_ours2:
 | 
				
			||||||
 | 
					            self.set_secondary(*key2, other.secondary[key2])
 | 
				
			||||||
 | 
					            if key2 in other.cache:
 | 
				
			||||||
 | 
					                self.cache[key2] = other.cache[key2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.primary.update(other.primary)
 | 
					 | 
				
			||||||
        self.secondary.update(other.secondary)
 | 
					 | 
				
			||||||
        self.cache.update(other.cache)
 | 
					 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def demote(self, key: str) -> None:
 | 
					    def demote(self, key: str) -> None:
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user