# Function works when called in Pluto, but not when copy-pasted into a package

**URL:** https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731
**Category:** New to Julia
**Tags:** question, package, pluto
**Created:** [April 15, 2026, 9:35pm UTC](https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731 "2026-04-15T21:35:29Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![CameraObscura42](https://avatars.discourse-cdn.com/v4/letter/c/f07891/32.png) [@CameraObscura42](https://discourse.julialang.org/u/CameraObscura42)
#### Post date: [April 15, 2026, 9:35pm UTC](https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731/1 "2026-04-15T21:35:29Z")

</div>

It’s going to take a while to extract a MWE from the package and pluto notebook, so I’ll post the question first in case I get lucky. Note that I am self-taught and relatively new to Julia, so my code is probably bad.

I’m writing a package for data analysis, part of which is using helium pycnometry to determine sample volume. Needing to get data analysis for an experiment done faster, I started with a Pluto notebook for a specific dataset and am working to make a general package using PlutoDevMacros and VSCodium to transfer functions from Pluto to the package. Every function except one copy/pasted easily.

The MethodError’s list of arguments matches the function call for the Pycnometry function (below). This worked fine in Pluto and is a direct copy-paste in the package. I get the same error message whether I call the function from Pluto or use a script in VSCodiuim.

As I read the error, It is an error calling the function and not a problem in the function. The arguments in parentheses match the keyword arguments I defined, but the arguments after that add an argument that I did not define or call: the true at the beginning I think the hexadecimal at the end relates to the MethodError and not the function call. I do not know where it comes from, and assume that addition means Julia can’t find a function with the correct arguments to call.

Does anyone know where those two arguments come from and what to do about it?

Note: I’ve deleted the actual dataframes from the output–it did not look like they would be readable. The warning is the output from my Catch statement.

```julia-auto
 Warning: function AnalyzeCellInjections!: Analysis Failed: MethodError(Core.kwcall, ((dry = false, InjectionGas = "helium", MaxItr = 100, InitialGuess = 25 mL, LeakAnalysis = true), true, 4×6 DataFrame, 4×10 DataFrame, 5.36 mL), 0x0000000000009925)

```

Function AnalyzeCellInjections below, the call to Pycnometry function is in the Try Catch near the end, data is stored in a struct for later output, cell.SourceInjectionData is the 4x6 dataframe in the error, and cell.InjectionData is the 4x10 dataframe

```julia-auto
function AnalyzeCellInjections!(Cells::OrderedDict{Symbol, CellDefinition}; Dry = true, Pycnometry = false, 
	ExpFactors::Union{Missing, Integer} = missing, MaxItr::Integer = 100, LeakAnalysis::Bool = false, 
	Delayed::Union{Missing, Dates.Period} = missing, InitialGuess = 25u"mL")

	for (key, cell) in pairs(Cells)
			@info "Processing " * string(cell.Description)
		if !cell.GasCell
			MatchSourceData!(Cells, key)
			FlagEquilibriumPeriods!(cell.Data, cell.Injections, :InjIn; EquilPeriod = cell.Param.EquilPeriod, Advance = cell.Param.IgnorePeriod, Delay = cell.Param.GCDelay, GasCell = cell.GasCell, Delayed = Delayed)

			if !ismissing(ExpFactors)	
				if ExpFactors == 2
					cell.ExpFactors = Get2ExpFactors(cell.Data, cell.Injections, ValidInj = cell.Param.ValidInj)
				elseif ExpFactors == 1
					cell.ExpFactors = Get1ExpFactors(cell.Data, cell.Injections, ValidInj = cell.Param.ValidInj)
				elseif ExpFactors == 0
					cell.ExpFactors = GetLines(cell.Data, cell.Injections, ValidInj = cell.Param.ValidInj)
				else
					@warn "function AnalyzeCellInjections!: Invalid number of exponentials specified"
				end
			end
			cell.InjectionData = GetInjectionData(cell.Data, cell.Injections, :InjIn, σₙ = Cells[cell.GasKey].σₙ, ExpFactors = cell.ExpFactors, GasCell = cell.GasCell, Delayed = ismissing(Delayed) ? false : true)
			try
				if Pycnometry
					cell.Volume, cell.AdjVolume, cell.CombinedData = Pycnometry(cell.SourceInjectionData, cell.InjectionData, 
						Cells[cell.GasKey].Volume; dry = Dry, InjectionGas = Cells[cell.GasKey].InjectionGas, MaxItr = MaxItr, 
						InitialGuess = InitialGuess, LeakAnalysis = LeakAnalysis
					)
				else
					cell.CombinedData = InjectionAnalyis(cell.SourceInjectionData, cell.InjectionData; InjectionGas = Cells[cell.GasKey].InjectionGas, SampleMass = cell.SampleMass, RamanDissolvedConc = cell.RamanDissolvedConc, WaterMass = cell.WaterMass, HeadSpaceVolume = cell.Volume, GasCellVolume = Cells[cell.GasKey].Volume, MolesHe = cell.MolesHe)
				end
			catch error
				@warn "function AnalyzeCellInjections!: Analysis Failed: " * string(error)
				@debug string(key) * " Injection Data"
				@debug cell.InjectionData[:, 3:6]
				@debug string(cell.GasKey) * " Injection Data"
				@debug cell.SourceInjectionData[:, 3:6]
			end
		end
	end
	return nothing
end 

```

Pycnometry function

```julia-auto
function Pycnometry(SourceInjectionData::DataFrame, TargetInjectionData::DataFrame, GasCellVolume::Quantities; 
    dry::Bool = true, InjectionGas::String = "helium", MaxItr::Integer = 100, InitialGuess::Quantities = 25u"ml", 
    LeakAnalysis::Bool = false)

	println("Pycnometry function called")

	InjectModel = SingleFluid(InjectionGas)
    HeN₂H₂O_GERG2008 = GERG2008(["helium", "nitrogen", "water"])
	
    #=
	drop uncertainty from measurements: Mole fractions must total 1.0 for Clapeyron (or use actual moles), 
    and the vector of mole fractions/moles does not work with the @uncertain macro to get uncertainties from 
    incompatible functions
    =#
	zForH2Ocalc = 1

	Tₒ = Measurements.value(TargetInjectionData.TargetTempBef[1])
	Pₒ = Measurements.value(TargetInjectionData.TargetPressBef[1])
	PP_H2O = PH2O(Tₒ) |> u"psi"

	if dry
		PP_H2O = 0u"psi"
		PP_N2 = Pₒ
		MF_H2O = PP_H2O / Pₒ
		MF_N2 = PP_N2 / Pₒ
		MF_He = 0 # not yet injected
		GasMixPre = [MF_He, MF_N2, MF_H2O]
	elseif Pₒ >= PP_H2O
		PP_N2 = Pₒ - PP_H2O
		MF_H2O = PP_H2O / Pₒ
		MF_N2 = PP_N2 / Pₒ
		MF_He = 0 # not yet injected
		GasMixPre = [MF_He, MF_N2, MF_H2O]
	else
		PP_N2 = 0u"psi"
		MF_H2O = 1
		MF_N2 = 0
		MF_He = 0 # not yet injected
		GasMixPre = [MF_He, MF_N2, MF_H2O] #assume entire pressure is water vapor
	end

	CombinedData = DataFrame()
	
	z = zFac(HeN₂H₂O_GERG2008, TargetInjectionData.TargetPressBef[1], TargetInjectionData.TargetTempBef[1], GasMixPre)
	TotalMolesBefore = MolesPresent(TargetInjectionData.TargetPressBef[1], TargetInjectionData.TargetTempBef[1], z, 
        InitialGuess
    ) |> u"mmol"

	CurrentVolume = InitialGuess
	PrevVolume = 0.0u"mL"
	if LeakAnalysis
		AdjCurrentVolume = InitialGuess
		AdjPrevVolume = 0.0u"mL"
		TotalMolesGasLeaked = zeros(nrow(TargetInjectionData)) .* u"mmol"
	else
		AdjCurrentVolume = InitialGuess
		AdjPrevVolume = InitialGuess
	end
	i = 0 # infinite loop break counter
	while (abs(PrevVolume - CurrentVolume) > 1e-10u"mL") || (abs(AdjPrevVolume - AdjCurrentVolume) > 1e-10u"mL")
		CombinedData = innerjoin(SourceInjectionData, TargetInjectionData, on = :Injection)
		PrevVolume = CurrentVolume
		AdjPrevVolume = AdjCurrentVolume
		@transform! CombinedData @astable begin
			:PSatH2O = dry ? (0u"psi" .* ones(nrow(CombinedData))) : PSat_H2Ounc.(:TargetTempAft)
			:MolesH2O = MolesPresent.(:PSatH2O, :TargetTempAft, zForH2Ocalc, CurrentVolume)
			:MolesN2BefPyc = TotalMolesBefore * MF_N2 .* ones(nrow(CombinedData))
			:zSourceBef = zFac.(InjectModel, :SourcePressBef, :SourceTempBef)
			:zSourceAft = zFac.(InjectModel, :SourcePressAft, :SourceTempAft)
			:SourceMolesGasBef = MolesPresent.(:SourcePressBef, :SourceTempBef, :zSourceBef, GasCellVolume) .|> u"mmol"
			:SourceMolesGasAft = MolesPresent.(:SourcePressAft, :SourceTempAft, :zSourceAft, GasCellVolume) .|> u"mmol"
			:MolesGasInjected = :SourceMolesGasBef - :SourceMolesGasAft .|> u"mmol"
			:TotalMolesGasInjected = cumsum(:MolesGasInjected) .|> u"mmol"
			:TotalMolesGasBefInj = :TotalMolesGasInjected - :MolesGasInjected
		end

		CombinedData.zTargetBef .= 1.0
		CombinedData.zTargetAft .= 1.0
		CombinedData.Volume .= (0.0±0.0)u"mL"
		if LeakAnalysis
			CombinedData.zAdjTargetAft .= 1.0
			CombinedData.AdjVolume .= (0.0±0.0)u"mL"
		end

		for (i, row) in enumerate(eachrow(CombinedData))
			if InjectionGas == "nitrogen"
				GasMixBef = Measurements.value.([0u"mmol", row.MolesN2BefPyc + row.TotalMolesGasBefInj, row.MolesH2O])
				GasMixAft = Measurements.value.([0u"mmol", row.MolesN2BefPyc + row.TotalMolesGasInjected, row.MolesH2O]) 
			else
				GasMixBef = Measurements.value.([row.TotalMolesGasBefInj, row.MolesN2BefPyc, row.MolesH2O])
				GasMixAft = Measurements.value.([row.TotalMolesGasInjected, row.MolesN2BefPyc, row.MolesH2O])
			end

			CombinedData.zTargetBef[i] = compressibility_factor(HeN₂H₂O_GERG2008, Measurements.value(row.TargetPressBef), 
                Measurements.value(row.TargetTempBef), GasMixBef
            )
			CombinedData.zTargetAft[i] = compressibility_factor(HeN₂H₂O_GERG2008, Measurements.value(row.TargetPressAft), 
                Measurements.value(row.TargetTempAft), GasMixAft
            )
			CombinedData.Volume[i] = PycVolume.(row.TargetPressAft, row.TargetTempAft, row.zTargetAft,  
                (row.MolesN2BefPyc + row.MolesH2O + row.TotalMolesGasInjected)
            )
		end

		if LeakAnalysis

			#need adj moles h20 and n2
			for (i, row) in enumerate(eachrow(CombinedData))					
				if InjectionGas == "nitrogen"
					AdjGasMixAft = Measurements.value.([0u"mmol", row.MolesN2BefPyc + row.TotalMolesGasInjected - 
                    TotalMolesGasLeaked[i], row.MolesH2O]
                    ) 
				else
					AdjGasMixAft = Measurements.value.([row.TotalMolesGasInjected - TotalMolesGasLeaked[i], 
                    row.MolesN2BefPyc, row.MolesH2O]
                    )
				end
				CombinedData.zAdjTargetAft[i] = compressibility_factor(HeN₂H₂O_GERG2008, 
                    Measurements.value(row.LeakRateAdjPressureAft), Measurements.value(row.TargetTempAft), AdjGasMixAft
                )
			end
			@transform! CombinedData @astable begin
				:MolesGasLeaked = MolesPresent.(:LeakRateAdjPressureAft, :TargetTempAft, :zAdjTargetAft, 
                    AdjCurrentVolume) - MolesPresent.(:TargetPressAft, :TargetTempAft, :zTargetAft, AdjCurrentVolume
                )
				:TotalMolesGasLeaked = cumsum(:MolesGasLeaked)
				:RemainingMolesGas = :TotalMolesGasInjected - :TotalMolesGasLeaked
				:InitialMolesGas = :RemainingMolesGas + :MolesGasLeaked
				:AdjVolume = PycVolume.(:LeakRateAdjPressureAft, :TargetTempAft, :zAdjTargetAft, :RemainingMolesGas)
			end
		end

		zForH2Ocalc = CombinedData.zTargetAft
		givenunit = unit(mean(CombinedData.Volume))
		CurrentVolume = weightedmean(ustrip.(CombinedData.Volume)) * givenunit
		if LeakAnalysis
			Adjgivenunit = unit(mean(CombinedData.AdjVolume))
			AdjCurrentVolume = weightedmean(ustrip.(CombinedData.AdjVolume)) * Adjgivenunit
			TotalMolesGasLeaked = CombinedData.TotalMolesGasLeaked
		end
		TotalMolesBefore = MolesPresent(CombinedData.TargetPressBef[1], CombinedData.TargetTempBef[1], 
            CombinedData.zTargetBef[1], CurrentVolume
        ) |> u"mmol"
		i += 1
		if i >= MaxItr
			@warn "Maximum Iterations reached"
			break
		end
	end
	@debug "Iterations: " * string(i)

    # weightedmean function gives the weighted mean of a set of measurements using inverses of variances as weights
	# weightedmean function is not compatible with units, get the given unit, strip it from the vector, 
    # calculate weighted mean and add the unit back
	givenunit = unit(mean(CombinedData.Volume)) #using the mean will cause errors if the units do not match
	TargetVolume = weightedmean(ustrip.(CombinedData.Volume)) * givenunit
	if LeakAnalysis
		Adjgivenunit = unit(mean(CombinedData.AdjVolume)) #using the mean will cause errors if the units do not match
		AdjTargetVolume = weightedmean(ustrip.(CombinedData.AdjVolume)) * Adjgivenunit
	else
		AdjTargetVolume = missing
	end
	return TargetVolume, AdjTargetVolume, CombinedData
end

```

---

<div class="post-metadata">

### Author: ![technocrat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/technocrat/32/220947_2.png) [@technocrat](https://discourse.julialang.org/u/technocrat)
#### Post date: [April 15, 2026, 10:37pm UTC](https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731/2 "2026-04-15T22:37:20Z")

</div>

By default, Pluto maintains its own environment using an embedded Project.toml/Manifest.toml separate from the global and project environments. If they are not on all fours with the package environment you are posting into, you would see this for any function that had a private dependency.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [April 16, 2026, 12:05am UTC](https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731/3 "2026-04-16T00:05:00Z")

</div>

That warning looked really off to me when I scrolled through it. It’s a bit ugly because of the keyworded call lowering, but it’s not hard to break down:

```julia-auto
MethodError(
Core.kwcall, # the lowered callable, not the source's
# keyword arguments, matches Pycnometry method
((dry = false, InjectionGas = "helium", MaxItr = 100, InitialGuess = 25 mL, LeakAnalysis = true),
# the original callable...huh?!
true,
# positional, dispatched arguments, matches Pycnometry method
4×6 DataFrame, 4×10 DataFrame, 5.36 mL),
0x0000000000009925) # world age, important to know but not for this

```

The original callable is obviously supposed to be the function `Pycnometry`, but instead it says `true`. The only call in your caller matching the keywords is:

```julia-auto
				if Pycnometry
					cell.Volume, cell.AdjVolume, cell.CombinedData = Pycnometry(cell.SourceInjectionData, cell.InjectionData, 
						Cells[cell.GasKey].Volume; dry = Dry, InjectionGas = Cells[cell.GasKey].InjectionGas, MaxItr = MaxItr, 
						InitialGuess = InitialGuess, LeakAnalysis = LeakAnalysis
					)

```

Well there’s a reasonable explanation for why `Pycnometry = true`, it’s a deliberate condition. It’s right in the caller’s arguments:

```julia-auto
function AnalyzeCellInjections!(Cells::OrderedDict{Symbol, CellDefinition};
Dry = true,
Pycnometry = false,

```

I’m surprised this ever worked in Pluto if simply copy-pasted. My initial assumption was Pluto’s soft-scoping (the major difference between source evaluated by various interactive contexts versus all other contexts or `eval`/`include`, has a documented and odd history), but an explicit local variable being used in a local scope instead of an outer and global variable of the same name is part of Julia’s scoping rules either way and is how variable shadowing generally works in lexically scoped languages. In this specific case, it’s impossible for the name `Pycnometry` to reference the `Bool` argument at `if Pycnometry` then the global function at `Pycnometry(...)`, Pluto or otherwise.

---

<div class="post-metadata">

### Author: ![CameraObscura42](https://avatars.discourse-cdn.com/v4/letter/c/f07891/32.png) [@CameraObscura42](https://discourse.julialang.org/u/CameraObscura42)
#### Post date: [April 16, 2026, 12:18am UTC](https://discourse.julialang.org/t/function-works-when-called-in-pluto-but-not-when-copy-pasted-into-a-package/136731/4 "2026-04-16T00:18:45Z")

</div>

Thanks for the help!
